Skip to content

Commit 3477f6b

Browse files
committed
Tree creation handler
1 parent 689d35c commit 3477f6b

File tree

3 files changed

+253
-0
lines changed

3 files changed

+253
-0
lines changed
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace ApiClients\Client\Github\CommandBus\Command\Repository;
4+
5+
use ApiClients\Client\Github\VO\NamedBlob;
6+
use WyriHaximus\Tactician\CommandHandler\Annotations\Handler;
7+
8+
/**
9+
* @Handler("ApiClients\Client\Github\CommandBus\Handler\Repository\TreeHandler")
10+
*/
11+
final class TreeCommand
12+
{
13+
/**
14+
* @var string
15+
*/
16+
private $repository;
17+
18+
/**
19+
* @var string|null
20+
*/
21+
private $baseTree;
22+
23+
/**
24+
* @var NamedBlob[]
25+
*/
26+
private $blobs;
27+
28+
/**
29+
* @param string $repository
30+
* @param string|null $baseTree
31+
* @param NamedBlob[] $blobs
32+
*/
33+
public function __construct(string $repository, ?string $baseTree, NamedBlob ...$blobs)
34+
{
35+
$this->repository = $repository;
36+
$this->baseTree = $baseTree;
37+
$this->blobs = $blobs;
38+
}
39+
40+
/**
41+
* @return string
42+
*/
43+
public function getRepository(): string
44+
{
45+
return $this->repository;
46+
}
47+
48+
/**
49+
* @return string|null
50+
*/
51+
public function getBaseTree(): ?string
52+
{
53+
return $this->baseTree;
54+
}
55+
56+
/**
57+
* @return NamedBlob[]
58+
*/
59+
public function getBlobs(): array
60+
{
61+
return $this->blobs;
62+
}
63+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace ApiClients\Client\Github\CommandBus\Handler\Repository;
4+
5+
use ApiClients\Client\Github\CommandBus\Command\Repository\TreeCommand;
6+
use ApiClients\Client\Github\Resource\Git\TreeInterface;
7+
use ApiClients\Client\Github\VO\NamedBlob;
8+
use ApiClients\Foundation\Hydrator\Hydrator;
9+
use ApiClients\Foundation\Transport\Service\RequestService;
10+
use Clue\React\Buzz\Message\ReadableBodyStream;
11+
use React\EventLoop\LoopInterface;
12+
use React\Promise\PromiseInterface;
13+
use RingCentral\Psr7\Request;
14+
use WyriHaximus\React\Stream\Json\JsonStream;
15+
16+
final class TreeHandler
17+
{
18+
/**
19+
* @var RequestService
20+
*/
21+
private $requestService;
22+
23+
/**
24+
* @var Hydrator
25+
*/
26+
private $hydrator;
27+
28+
/**
29+
* @var LoopInterface
30+
*/
31+
private $loop;
32+
33+
/**
34+
* @param RequestService $requestService
35+
* @param Hydrator $hydrator
36+
* @param LoopInterface $loop
37+
*/
38+
public function __construct(RequestService $requestService, Hydrator $hydrator, LoopInterface $loop)
39+
{
40+
$this->requestService = $requestService;
41+
$this->hydrator = $hydrator;
42+
$this->loop = $loop;
43+
}
44+
45+
/**
46+
* @param TreeCommand $command
47+
* @return PromiseInterface
48+
*/
49+
public function handle(TreeCommand $command): PromiseInterface
50+
{
51+
$stream = new JsonStream();
52+
$this->loop->futureTick(function () use ($stream, $command) {
53+
if ($command->getBaseTree() !== null) {
54+
$stream->write('base_tree', $command->getBaseTree());
55+
}
56+
57+
$trees = JsonStream::createArray();
58+
$stream->write('tree', $trees);
59+
$stream->end();
60+
61+
$this->loop->futureTick(function () use ($trees, $command) {
62+
/** @var NamedBlob $blob */
63+
foreach ($command->getBlobs() as $blob) {
64+
$node = [
65+
'path' => $blob->getPath(),
66+
'mode' => $blob->getMode(),
67+
'type' => $blob->getType(),
68+
];
69+
70+
if ($blob->getSha() !== null) {
71+
$node['sha'] = $blob->getSha();
72+
}
73+
74+
if ($blob->getContent() !== null) {
75+
$node['content'] = $blob->getContent();
76+
}
77+
78+
$trees->writeValue($node);
79+
}
80+
$trees->close();
81+
});
82+
});
83+
84+
return $this->requestService->request(
85+
new Request(
86+
'POST',
87+
'repos/' . $command->getRepository() . '/git/trees',
88+
[],
89+
new ReadableBodyStream($stream)
90+
)
91+
)->then(function ($tree) {
92+
return $this->hydrator->hydrate(TreeInterface::HYDRATE_CLASS, $tree->getBody()->getParsedContents());
93+
});
94+
}
95+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace ApiClients\Tests\Github\CommandBus\Handler\Repository;
4+
5+
use ApiClients\Client\Github\CommandBus\Command\Repository\TreeCommand;
6+
use ApiClients\Client\Github\CommandBus\Handler\Repository\TreeHandler;
7+
use ApiClients\Client\Github\Resource\Git\TreeInterface;
8+
use ApiClients\Client\Github\VO\NamedBlob;
9+
use ApiClients\Foundation\Hydrator\Hydrator;
10+
use ApiClients\Foundation\Transport\Service\RequestService;
11+
use ApiClients\Middleware\Json\JsonStream;
12+
use ApiClients\Tools\TestUtilities\TestCase;
13+
use Prophecy\Argument;
14+
use Psr\Http\Message\RequestInterface;
15+
use React\EventLoop\Factory;
16+
use function React\Promise\Stream\buffer;
17+
use RingCentral\Psr7\Response;
18+
use function WyriHaximus\React\timedPromise;
19+
20+
/**
21+
* @internal
22+
*/
23+
final class TreeHandlerTest extends TestCase
24+
{
25+
public function provideCommands()
26+
{
27+
yield [
28+
function () {
29+
$loop = Factory::create();
30+
$blob = new NamedBlob(
31+
'file.name',
32+
'100644',
33+
'blob',
34+
'sha512',
35+
null
36+
);
37+
$command = new TreeCommand(
38+
'login/repo',
39+
'sha1234567890',
40+
$blob
41+
);
42+
$expectedJson = [
43+
'base_tree' => 'sha1234567890',
44+
'tree' => [
45+
[
46+
'path' => 'file.name',
47+
'mode' => '100644',
48+
'type' => 'blob',
49+
'sha' => 'sha512',
50+
],
51+
],
52+
];
53+
54+
return [$loop, $command, $expectedJson];
55+
},
56+
];
57+
}
58+
59+
/**
60+
* @dataProvider provideCommands
61+
*/
62+
public function testCommand(callable $callable)
63+
{
64+
list($loop, $command, $expectedjson) = $callable();
65+
$json = [
66+
'foo' => 'bar',
67+
];
68+
$stream = null;
69+
$jsonStream = new JsonStream($json);
70+
71+
$tree = $this->prophesize(TreeInterface::class)->reveal();
72+
73+
$requestService = $this->prophesize(RequestService::class);
74+
$requestService->request(Argument::that(function (RequestInterface $request) use (&$stream) {
75+
buffer($request->getBody())->done(function ($json) use (&$stream) {
76+
$stream = $json;
77+
});
78+
79+
return true;
80+
}))->willReturn(timedPromise($loop, 1, new Response(
81+
200,
82+
[],
83+
$jsonStream
84+
)));
85+
86+
$hydrator = $this->prophesize(Hydrator::class);
87+
$hydrator->hydrate(TreeInterface::HYDRATE_CLASS, $json)->shouldBeCalled()->willReturn($tree);
88+
89+
$handler = new TreeHandler($requestService->reveal(), $hydrator->reveal(), $loop);
90+
91+
$result = $this->await($handler->handle($command), $loop);
92+
self::assertSame($tree, $result);
93+
self::assertSame($expectedjson, \json_decode($stream, true));
94+
}
95+
}

0 commit comments

Comments
 (0)