From 9872b12abdc3406059d53a78b435c87c5f8b8b2e Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sat, 28 Mar 2020 14:50:14 +0100 Subject: [PATCH 1/9] remove useless script --- composer.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/composer.json b/composer.json index 0e7601c..5071f2a 100644 --- a/composer.json +++ b/composer.json @@ -42,9 +42,6 @@ "phpunit/phpunit": "~8.0", "giorgiosironi/eris": "^0.11.0" }, - "scripts": { - "test": "vendor/bin/phpunit --colors=always" - }, "bin": ["tower"], "extra": { "gene": { From 200157c068255804f0e3d27b1678638c37f56f74 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sat, 28 Mar 2020 14:53:20 +0100 Subject: [PATCH 2/9] require php 7.4 --- composer.json | 2 +- src/Command/Listen.php | 6 +++--- src/Command/Ping.php | 4 ++-- src/Command/Trigger.php | 2 +- src/Configuration.php | 6 +++--- src/Configuration/Yaml.php | 4 ++-- src/EnvironmentVariable.php | 4 ++-- src/Exception/ActionFailed.php | 2 +- src/Listener/Ping.php | 2 +- src/Neighbour.php | 6 +++--- src/Neighbour/Name.php | 2 +- src/Ping/Delegate.php | 2 +- src/Ping/Ssh.php | 2 +- src/Ping/Tcp.php | 2 +- src/Run.php | 6 +++--- 15 files changed, 26 insertions(+), 26 deletions(-) diff --git a/composer.json b/composer.json index 5071f2a..d4309e4 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ "issues": "http://github.com/Innmind/Tower/issues" }, "require": { - "php": "~7.2", + "php": "~7.4", "innmind/immutable": "^2.8", "innmind/url": "^2.0", "symfony/config": "^4.0", diff --git a/src/Command/Listen.php b/src/Command/Listen.php index c35f512..4855cc0 100644 --- a/src/Command/Listen.php +++ b/src/Command/Listen.php @@ -23,9 +23,9 @@ final class Listen implements Command { - private $ports; - private $server; - private $loop; + private Ports $ports; + private Server $server; + private Loop $loop; public function __construct(Ports $ports, Server $server, Loop $loop) { diff --git a/src/Command/Ping.php b/src/Command/Ping.php index e40d5b5..c9fd148 100644 --- a/src/Command/Ping.php +++ b/src/Command/Ping.php @@ -22,8 +22,8 @@ final class Ping implements Command { - private $configuration; - private $ping; + private Configuration $configuration; + private ServerPing $ping; public function __construct(Configuration $configuration, ServerPing $ping) { diff --git a/src/Command/Trigger.php b/src/Command/Trigger.php index cfa3d60..960ea99 100644 --- a/src/Command/Trigger.php +++ b/src/Command/Trigger.php @@ -18,7 +18,7 @@ final class Trigger implements Command { - private $run; + private Run $run; public function __construct(Run $run) { diff --git a/src/Configuration.php b/src/Configuration.php index d3c4309..98ee3df 100644 --- a/src/Configuration.php +++ b/src/Configuration.php @@ -9,9 +9,9 @@ final class Configuration { - private $neighbours; - private $exports; - private $actions; + private SetInterface $neighbours; + private SetInterface $exports; + private SetInterface $actions; public function __construct( SetInterface $neighbours, diff --git a/src/Configuration/Yaml.php b/src/Configuration/Yaml.php index 0c96cb7..5867a60 100644 --- a/src/Configuration/Yaml.php +++ b/src/Configuration/Yaml.php @@ -18,8 +18,8 @@ final class Yaml implements Loader { - private $processor; - private $config; + private Processor $processor; + private Schema $config; public function __construct() { diff --git a/src/EnvironmentVariable.php b/src/EnvironmentVariable.php index 63807d6..40c01ff 100644 --- a/src/EnvironmentVariable.php +++ b/src/EnvironmentVariable.php @@ -10,8 +10,8 @@ final class EnvironmentVariable { private const PATTERN = '~^(?[A-Z0-9_]+)=(?.*)$~'; - private $name; - private $value; + private string $name; + private string $value; public function __construct(string $value) { diff --git a/src/Exception/ActionFailed.php b/src/Exception/ActionFailed.php index 9a14a26..83dbf9f 100644 --- a/src/Exception/ActionFailed.php +++ b/src/Exception/ActionFailed.php @@ -7,7 +7,7 @@ final class ActionFailed extends RuntimeException { - private $process; + private Process $process; public function __construct(string $action, Process $process) { diff --git a/src/Listener/Ping.php b/src/Listener/Ping.php index bd6a1dc..6459144 100644 --- a/src/Listener/Ping.php +++ b/src/Listener/Ping.php @@ -9,7 +9,7 @@ final class Ping { - private $run; + private Run $run; public function __construct(Run $run) { diff --git a/src/Neighbour.php b/src/Neighbour.php index f6f24a9..c490555 100644 --- a/src/Neighbour.php +++ b/src/Neighbour.php @@ -12,9 +12,9 @@ final class Neighbour { - private $name; - private $url; - private $tags; + private Name $name; + private UrlInterface $url; + private Set $tags; public function __construct(Name $name, UrlInterface $url, string ...$tags) { diff --git a/src/Neighbour/Name.php b/src/Neighbour/Name.php index f8e3777..d0028dc 100644 --- a/src/Neighbour/Name.php +++ b/src/Neighbour/Name.php @@ -8,7 +8,7 @@ final class Name { - private $value; + private string $value; public function __construct(string $value) { diff --git a/src/Ping/Delegate.php b/src/Ping/Delegate.php index 49821ad..dc2b581 100644 --- a/src/Ping/Delegate.php +++ b/src/Ping/Delegate.php @@ -12,7 +12,7 @@ final class Delegate implements Ping { - private $pings; + private MapInterface $pings; public function __construct(MapInterface $pings) { diff --git a/src/Ping/Ssh.php b/src/Ping/Ssh.php index 9d1dfb0..91dcb26 100644 --- a/src/Ping/Ssh.php +++ b/src/Ping/Ssh.php @@ -12,7 +12,7 @@ final class Ssh implements Ping { - private $remote; + private Remote $remote; public function __construct(Remote $remote) { diff --git a/src/Ping/Tcp.php b/src/Ping/Tcp.php index 0450988..b31232c 100644 --- a/src/Ping/Tcp.php +++ b/src/Ping/Tcp.php @@ -14,7 +14,7 @@ final class Tcp implements Ping { - private $remote; + private Remote $remote; public function __construct(Remote $remote) { diff --git a/src/Run.php b/src/Run.php index 981fd77..ba9376d 100644 --- a/src/Run.php +++ b/src/Run.php @@ -15,9 +15,9 @@ final class Run { - private $processes; - private $configuration; - private $ping; + private Server\Processes $processes; + private Configuration $configuration; + private Ping $ping; public function __construct( Server $server, From 7f9cd97fdb935e71143322fd5f50d833b4dc3928 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sat, 28 Mar 2020 15:28:26 +0100 Subject: [PATCH 3/9] update deps --- composer.json | 15 ++++++----- src/Command/Listen.php | 18 ++++++------- src/Command/Ping.php | 18 +++++++------ src/Command/Trigger.php | 10 ++++---- src/Configuration.php | 33 ++++++++++++------------ src/Configuration/Loader.php | 4 +-- src/Configuration/Schema.php | 4 +-- src/Configuration/Yaml.php | 8 +++--- src/EnvironmentVariable.php | 6 ++--- src/Listener/Ping.php | 6 ++--- src/Neighbour.php | 17 ++++++------- src/Ping/Delegate.php | 10 ++++---- src/Ping/Ssh.php | 2 +- src/Ping/Tcp.php | 18 ++++++------- src/Run.php | 13 +++++----- src/bootstrap.php | 19 +++++++------- tests/BootstrapTest.php | 4 ++- tests/Command/ListenTest.php | 43 ++++++++++++++++---------------- tests/Command/PingTest.php | 16 ++++++------ tests/Command/TriggerTest.php | 10 ++++---- tests/Configuration/YamlTest.php | 16 +++++++----- tests/ConfigurationTest.php | 7 +++--- tests/Listener/PingTest.php | 22 ++++++++++------ tests/NeighbourTest.php | 11 ++++---- tests/Ping/DelegateTest.php | 18 ++++++------- tests/Ping/SshTest.php | 6 ++--- tests/Ping/TcpTest.php | 2 +- tests/RunTest.php | 35 +++++++++++--------------- tower | 12 ++++++--- 29 files changed, 204 insertions(+), 199 deletions(-) diff --git a/composer.json b/composer.json index d4309e4..4644be7 100644 --- a/composer.json +++ b/composer.json @@ -16,15 +16,14 @@ }, "require": { "php": "~7.4", - "innmind/immutable": "^2.8", - "innmind/url": "^2.0", - "symfony/config": "^4.0", - "symfony/yaml": "^4.0", - "innmind/server-control": "^2.2", - "innmind/socket": "^2.0", - "innmind/cli": "^1.2", + "innmind/immutable": "~3.5", + "innmind/url": "~3.3", + "symfony/config": "~5.0", + "symfony/yaml": "~5.0", + "innmind/operating-system": "~2.0", + "innmind/cli": "~2.0", "innmind/json": "^1.1", - "innmind/silent-cartographer": "^1.1" + "innmind/silent-cartographer": "~2.0" }, "autoload": { "psr-4": { diff --git a/src/Command/Listen.php b/src/Command/Listen.php index 4855cc0..5077026 100644 --- a/src/Command/Listen.php +++ b/src/Command/Listen.php @@ -15,7 +15,7 @@ }; use Innmind\Socket\{ Internet\Transport, - Loop, + Serve, }; use Innmind\OperatingSystem\Ports; use Innmind\IP\IPv4; @@ -25,13 +25,13 @@ final class Listen implements Command { private Ports $ports; private Server $server; - private Loop $loop; + private Serve $serve; - public function __construct(Ports $ports, Server $server, Loop $loop) + public function __construct(Ports $ports, Server $server, Serve $serve) { $this->ports = $ports; $this->server = $server; - $this->loop = $loop; + $this->serve = $serve; } public function __invoke(Environment $env, Arguments $arguments, Options $options): void @@ -44,7 +44,7 @@ public function __invoke(Environment $env, Arguments $arguments, Options $option ServerCommand::background('tower') ->withArgument('listen') ->withArgument($arguments->get('port')) - ->withWorkingDirectory((string) $env->workingDirectory()) + ->withWorkingDirectory($env->workingDirectory()) ); return; @@ -54,11 +54,11 @@ public function __invoke(Environment $env, Arguments $arguments, Options $option try { $socket = $this->ports->open( Transport::tcp(), - new IPv4('127.0.0.1'), - new Port((int) $arguments->get('port')) + IPv4::of('127.0.0.1'), + Port::of((int) $arguments->get('port')) ); - ($this->loop)($socket); + ($this->serve)($socket); } catch (\Throwable $e) { //pass } @@ -66,7 +66,7 @@ public function __invoke(Environment $env, Arguments $arguments, Options $option } while (true); } - public function __toString(): string + public function toString(): string { return <<get('server'); - $neighbour = $this + $neighbour = first($this ->configuration ->neighbours() ->filter(static function(Neighbour $neighbour) use ($name): bool { return (string) $neighbour->name() === $name; - }) - ->current(); + })); $tags = []; @@ -49,16 +51,16 @@ public function __invoke(Environment $env, Arguments $arguments, Options $option ->split(',') ->reduce( Set::of('string'), - static function(SetInterface $tags, Str $tag): SetInterface { - return $tags->add((string) $tag->trim()); + static function(Set $tags, Str $tag): Set { + return $tags->add($tag->trim()->toString()); } ); } - ($this->ping)($neighbour, ...$tags); + ($this->ping)($neighbour, ...unwrap($tags)); } - public function __toString(): string + public function toString(): string { return <<split(',') ->reduce( Set::of('string'), - static function(SetInterface $tags, Str $tag): SetInterface { - return $tags->add((string) $tag->trim()); + static function(Set $tags, Str $tag): Set { + return $tags->add($tag->trim()->toString()); } ); } - ($this->run)(...$tags); + ($this->run)(...unwrap($tags)); } - public function __toString(): string + public function toString(): string { return <<type() !== Neighbour::class) { throw new \TypeError(sprintf( - 'Argument 1 must be of type SetInterface<%s>', + 'Argument 1 must be of type Set<%s>', Neighbour::class )); } if ((string) $exports->type() !== 'string') { - throw new \TypeError('Argument 2 must be of type SetInterface'); + throw new \TypeError('Argument 2 must be of type Set'); } if ((string) $actions->type() !== 'string') { - throw new \TypeError('Argument 3 must be of type SetInterface'); + throw new \TypeError('Argument 3 must be of type Set'); } $this->neighbours = $neighbours; @@ -39,25 +38,25 @@ public function __construct( } /** - * @return SetInterface + * @return Set */ - public function neighbours(): SetInterface + public function neighbours(): Set { return $this->neighbours; } /** - * @return SetInterface + * @return Set */ - public function exports(): SetInterface + public function exports(): Set { return $this->exports; } /** - * @return SetInterface + * @return Set */ - public function actions(): SetInterface + public function actions(): Set { return $this->actions; } diff --git a/src/Configuration/Loader.php b/src/Configuration/Loader.php index 947c8b0..27da70d 100644 --- a/src/Configuration/Loader.php +++ b/src/Configuration/Loader.php @@ -4,9 +4,9 @@ namespace Innmind\Tower\Configuration; use Innmind\Tower\Configuration; -use Innmind\Url\PathInterface; +use Innmind\Url\Path; interface Loader { - public function __invoke(PathInterface $configPath): Configuration; + public function __invoke(Path $configPath): Configuration; } diff --git a/src/Configuration/Schema.php b/src/Configuration/Schema.php index 99159c4..3f51c48 100644 --- a/src/Configuration/Schema.php +++ b/src/Configuration/Schema.php @@ -12,8 +12,8 @@ final class Schema implements ConfigurationInterface { public function getConfigTreeBuilder() { - $builder = new TreeBuilder; - $root = $builder->root('tower'); + $builder = new TreeBuilder('tower'); + $root = $builder->getRootNode(); $root ->children() diff --git a/src/Configuration/Yaml.php b/src/Configuration/Yaml.php index 5867a60..2a94edd 100644 --- a/src/Configuration/Yaml.php +++ b/src/Configuration/Yaml.php @@ -10,7 +10,7 @@ }; use Innmind\Url\{ Url, - PathInterface, + Path, }; use Innmind\Immutable\Set; use Symfony\Component\Config\Definition\Processor; @@ -27,11 +27,11 @@ public function __construct() $this->config = new Schema; } - public function __invoke(PathInterface $configPath): Configuration + public function __invoke(Path $configPath): Configuration { $config = $this->processor->processConfiguration( $this->config, - [Parser::parseFile((string) $configPath)] + [Parser::parseFile($configPath->toString())] ); $neighbours = Set::of(Neighbour::class); @@ -39,7 +39,7 @@ public function __invoke(PathInterface $configPath): Configuration $neighbours = $neighbours->add( new Neighbour( new Name($name), - Url::fromString($value['url']), + Url::of($value['url']), ...$value['tags'] ) ); diff --git a/src/EnvironmentVariable.php b/src/EnvironmentVariable.php index 40c01ff..77c7fbf 100644 --- a/src/EnvironmentVariable.php +++ b/src/EnvironmentVariable.php @@ -18,13 +18,13 @@ public function __construct(string $value) $value = Str::of($value); if (!$value->matches(self::PATTERN)) { - throw new DomainException((string) $value); + throw new DomainException($value->toString()); } $parts = $value->capture(self::PATTERN); - $this->name = (string) $parts->get('name'); - $this->value = (string) $parts->get('value'); + $this->name = $parts->get('name')->toString(); + $this->value = $parts->get('value')->toString(); } public function name(): string diff --git a/src/Listener/Ping.php b/src/Listener/Ping.php index 6459144..fbbb76a 100644 --- a/src/Listener/Ping.php +++ b/src/Listener/Ping.php @@ -4,7 +4,7 @@ namespace Innmind\Tower\Listener; use Innmind\Tower\Run; -use Innmind\Socket\Event\DataReceived; +use Innmind\Socket\Event\ConnectionReady; use Innmind\Json\Json; final class Ping @@ -16,9 +16,9 @@ public function __construct(Run $run) $this->run = $run; } - public function __invoke(DataReceived $event): void + public function __invoke(ConnectionReady $event): void { - $payload = Json::decode((string) $event->data()); + $payload = Json::decode($event->connection()->read()->toString()); if (!\is_array($payload)) { return; diff --git a/src/Neighbour.php b/src/Neighbour.php index c490555..ea84dd6 100644 --- a/src/Neighbour.php +++ b/src/Neighbour.php @@ -4,19 +4,16 @@ namespace Innmind\Tower; use Innmind\Tower\Neighbour\Name; -use Innmind\Url\UrlInterface; -use Innmind\Immutable\{ - SetInterface, - Set, -}; +use Innmind\Url\Url; +use Innmind\Immutable\Set; final class Neighbour { private Name $name; - private UrlInterface $url; + private Url $url; private Set $tags; - public function __construct(Name $name, UrlInterface $url, string ...$tags) + public function __construct(Name $name, Url $url, string ...$tags) { $this->name = $name; $this->url = $url; @@ -28,15 +25,15 @@ public function name(): Name return $this->name; } - public function url(): UrlInterface + public function url(): Url { return $this->url; } /** - * @return SetInterface + * @return Set */ - public function tags(): SetInterface + public function tags(): Set { return $this->tags; } diff --git a/src/Ping/Delegate.php b/src/Ping/Delegate.php index dc2b581..7a7ed67 100644 --- a/src/Ping/Delegate.php +++ b/src/Ping/Delegate.php @@ -8,20 +8,20 @@ Neighbour, Exception\SchemeNotSupported, }; -use Innmind\Immutable\MapInterface; +use Innmind\Immutable\Map; final class Delegate implements Ping { - private MapInterface $pings; + private Map $pings; - public function __construct(MapInterface $pings) + public function __construct(Map $pings) { if ( (string) $pings->keyType() !== 'string' || (string) $pings->valueType() !== Ping::class ) { throw new \TypeError(sprintf( - 'Argument 1 must be of type MapInterface', + 'Argument 1 must be of type Map', Ping::class )); } @@ -31,7 +31,7 @@ public function __construct(MapInterface $pings) public function __invoke(Neighbour $neighbour, string ...$tags): void { - $scheme = (string) $neighbour->url()->scheme(); + $scheme = $neighbour->url()->scheme()->toString(); if (!$this->pings->contains($scheme)) { throw new SchemeNotSupported($scheme); diff --git a/src/Ping/Ssh.php b/src/Ping/Ssh.php index 91dcb26..8a82a20 100644 --- a/src/Ping/Ssh.php +++ b/src/Ping/Ssh.php @@ -29,7 +29,7 @@ public function __invoke(Neighbour $neighbour, string ...$tags): void Command::background('tower') ->withArgument('trigger') ->withOption('tags', implode(',', $tags)) - ->withWorkingDirectory((string) $neighbour->url()->path()) + ->withWorkingDirectory($neighbour->url()->path()) ); } } diff --git a/src/Ping/Tcp.php b/src/Ping/Tcp.php index b31232c..21542b2 100644 --- a/src/Ping/Tcp.php +++ b/src/Ping/Tcp.php @@ -23,15 +23,13 @@ public function __construct(Remote $remote) public function __invoke(Neighbour $neighbour, string ...$tags): void { - $this - ->remote - ->socket( - Transport::tcp(), - $neighbour->url()->authority() - ) - ->write(Str::of(Json::encode([ - 'tags' => $tags, - ]))) - ->close(); + $socket = $this->remote->socket( + Transport::tcp(), + $neighbour->url()->authority() + ); + $socket->write(Str::of(Json::encode([ + 'tags' => $tags, + ]))); + $socket->close(); } } diff --git a/src/Run.php b/src/Run.php index ba9376d..c509585 100644 --- a/src/Run.php +++ b/src/Run.php @@ -45,7 +45,8 @@ static function(Command $command, EnvironmentVariable $env): Command { ); } ); - $process = $this->processes->execute($command)->wait(); + $process = $this->processes->execute($command); + $process->wait(); if (!$process->exitCode()->isSuccessful()) { throw new ActionFailed($action, $process); @@ -79,14 +80,12 @@ static function(Command $command, EnvironmentVariable $env): Command { ); } ); - $output = (string) $this - ->processes - ->execute($command) - ->wait() - ->output(); + $process = $this->processes->execute($command); + $process->wait(); + $output = $process->output()->toString(); return $envs->add(new EnvironmentVariable( - (string) Str::of($output)->trim() + Str::of($output)->trim()->toString(), )); } ); diff --git a/src/bootstrap.php b/src/bootstrap.php index 22f5d88..736249e 100644 --- a/src/bootstrap.php +++ b/src/bootstrap.php @@ -4,21 +4,21 @@ namespace Innmind\Tower; use Innmind\Server\Control\Server; -use Innmind\Url\PathInterface; +use Innmind\Url\Path; use Innmind\Socket\{ - Loop, - Event\DataReceived, + Serve, + Event\ConnectionReady, }; use Innmind\CLI\Commands; use Innmind\OperatingSystem\{ Remote, Ports, + Sockets, }; use Innmind\EventBus\EventBus; -use Innmind\TimeContinuum\ElapsedPeriod; +use Innmind\TimeContinuum\Earth\ElapsedPeriod; use Innmind\Immutable\{ Map, - SetInterface, Set, }; @@ -26,7 +26,8 @@ function bootstrap( Server $server, Remote $remote, Ports $ports, - PathInterface $config + Sockets $sockets, + Path $config ): Commands { $configuration = (new Configuration\Yaml)($config); $ping = new Ping\Delegate( @@ -36,12 +37,12 @@ function bootstrap( ); $run = new Run($server, $configuration, $ping); - $loop = new Loop( + $loop = new Serve( new EventBus\Map( Map::of('string', 'callable') - (DataReceived::class, new Listener\Ping($run)) + (ConnectionReady::class, new Listener\Ping($run)) ), - new ElapsedPeriod(3600000) // 1 hour + $sockets->watch(new ElapsedPeriod(3600000)), // 1 hour ); return new Commands( diff --git a/tests/BootstrapTest.php b/tests/BootstrapTest.php index d043864..63f5791 100644 --- a/tests/BootstrapTest.php +++ b/tests/BootstrapTest.php @@ -10,6 +10,7 @@ use Innmind\OperatingSystem\{ Remote, Ports, + Sockets, }; use PHPUnit\Framework\TestCase; @@ -21,7 +22,8 @@ public function testInvokation() $this->createMock(Server::class), $this->createMock(Remote::class), $this->createMock(Ports::class), - new Path('config/config.yml.dist') + $this->createMock(Sockets::class), + Path::of('config/config.yml.dist') ); $this->assertInstanceOf(Commands::class, $commands); diff --git a/tests/Command/ListenTest.php b/tests/Command/ListenTest.php index 5b2265d..d413f7e 100644 --- a/tests/Command/ListenTest.php +++ b/tests/Command/ListenTest.php @@ -19,12 +19,12 @@ Server\Command as ServerCommand, }; use Innmind\Socket\{ - Loop, + Serve, Client\Internet, Internet\Transport, }; +use Innmind\Stream\Watch; use Innmind\EventBus\EventBus; -use Innmind\TimeContinuum\ElapsedPeriod; use Innmind\Url\{ Path, Url, @@ -45,9 +45,9 @@ public function testInterface() new Listen( $this->createMock(Ports::class), $this->createMock(Server::class), - new Loop( + new Serve( $this->createMock(EventBus::class), - new ElapsedPeriod(42) + $this->createMock(Watch::class), ) ) ); @@ -58,9 +58,9 @@ public function testDaemonize() $listen = new Listen( $this->createMock(Ports::class), $server = $this->createMock(Server::class), - new Loop( + new Serve( $this->createMock(EventBus::class), - new ElapsedPeriod(42) + $this->createMock(Watch::class), ) ); $server @@ -71,26 +71,26 @@ public function testDaemonize() ->expects($this->once()) ->method('execute') ->with($this->callback(static function($command): bool { - return (string) $command === "tower 'listen' '1337'" && + return $command->toString() === "tower 'listen' '1337'" && $command->toBeRunInBackground() && - $command->workingDirectory() === '/working/directory'; + $command->workingDirectory()->toString() === '/working/directory'; })); $env = $this->createMock(Environment::class); $env ->expects($this->once()) ->method('workingDirectory') - ->willReturn(new Path('/working/directory')); + ->willReturn(Path::of('/working/directory')); $this->assertNull($listen( $env, new Arguments( - (new Map('string', 'mixed')) - ->put('port', '1337') + Map::of('string', 'string') + ('port', '1337') ), new Options( - (new Map('string', 'mixed')) - ->put('daemon', true) + Map::of('string', 'string') + ('daemon', '') ) )); } @@ -104,7 +104,7 @@ public function testInvoke() ServerCommand::foreground('./tower') ->withArgument('listen') ->withArgument('1337') - ->withWorkingDirectory(getcwd()) + ->withWorkingDirectory(Path::of(getcwd().'/')) ->withEnvironment('TOWER_CONFIG', 'config/config.yml.dist') ); @@ -113,11 +113,10 @@ public function testInvoke() $client = new Internet( Transport::tcp(), - Url::fromString('//127.0.0.1:1337')->authority() + Url::of('//127.0.0.1:1337')->authority() ); - $client - ->write(Str::of('{"tags":[]}')) - ->close(); + $client->write(Str::of('{"tags":[]}')); + $client->close(); $this->assertTrue($process->isRunning()); posix_kill($process->pid()->toInt(), SIGKILL); @@ -135,14 +134,14 @@ public function testUsage() $this->assertSame( $expected, - (string) new Listen( + (new Listen( $this->createMock(Ports::class), $this->createMock(Server::class), - new Loop( + new Serve( $this->createMock(EventBus::class), - new ElapsedPeriod(42) + $this->createMock(Watch::class), ) - ) + ))->toString() ); } } diff --git a/tests/Command/PingTest.php b/tests/Command/PingTest.php index 5e1cf11..406a073 100644 --- a/tests/Command/PingTest.php +++ b/tests/Command/PingTest.php @@ -48,11 +48,11 @@ public function testInvoke() Neighbour::class, new Neighbour( new Name('foo'), - Url::fromString('example.com') + Url::of('example.com') ), $expected = new Neighbour( new Name('bar'), - Url::fromString('example2.com') + Url::of('example2.com') ) ), Set::of('string'), @@ -68,12 +68,12 @@ public function testInvoke() $this->assertNull($ping( $this->createMock(Environment::class), new Arguments( - (new Map('string', 'mixed')) - ->put('server', 'bar') + Map::of('string', 'string') + ('server', 'bar') ), new Options( - (new Map('string', 'mixed')) - ->put('tags', 'foobar , baz') + Map::of('string', 'string') + ('tags', 'foobar , baz') ) )); } @@ -92,14 +92,14 @@ public function testUsage() $this->assertSame( $expected, - (string) new Ping( + (new Ping( new Configuration( Set::of(Neighbour::class), Set::of('string'), Set::of('string') ), $this->createMock(ServerPing::class) - ) + ))->toString() ); } } diff --git a/tests/Command/TriggerTest.php b/tests/Command/TriggerTest.php index 2fae9ee..c48dfd2 100644 --- a/tests/Command/TriggerTest.php +++ b/tests/Command/TriggerTest.php @@ -55,7 +55,7 @@ public function testInvoke() Neighbour::class, $neighbour = new Neighbour( new Name('foo'), - Url::fromString('example.com'), + Url::of('example.com'), 'foo' ) ), @@ -74,8 +74,8 @@ public function testInvoke() $this->createMock(Environment::class), new Arguments, new Options( - (new Map('string', 'mixed')) - ->put('tags', 'foo , bar') + Map::of('string', 'string') + ('tags', 'foo , bar') ) )); } @@ -93,7 +93,7 @@ public function testUsage() $this->assertSame( $expected, - (string) new Trigger( + (new Trigger( new Run( $this->createMock(Server::class), new Configuration( @@ -103,7 +103,7 @@ public function testUsage() ), $this->createMock(Ping::class) ) - ) + ))->toString() ); } } diff --git a/tests/Configuration/YamlTest.php b/tests/Configuration/YamlTest.php index 056f24e..0ea3c9b 100644 --- a/tests/Configuration/YamlTest.php +++ b/tests/Configuration/YamlTest.php @@ -9,6 +9,10 @@ Configuration, }; use Innmind\Url\Path; +use function Innmind\Immutable\{ + first, + unwrap, +}; use PHPUnit\Framework\TestCase; class YamlTest extends TestCase @@ -20,22 +24,22 @@ public function testInterface() public function testInvoke() { - $config = (new Yaml)(new Path('config/config.yml.dist')); + $config = (new Yaml)(Path::of('config/config.yml.dist')); $this->assertInstanceOf(Configuration::class, $config); $this->assertCount(1, $config->neighbours()); $this->assertSame( '_name_', - (string) $config->neighbours()->current()->name() + (string) first($config->neighbours())->name() ); $this->assertSame( 'ssh://example.com:80/path/to/config/on/neighbour/server.yml', - (string) $config->neighbours()->current()->url() + first($config->neighbours())->url()->toString() ); - $this->assertSame(['foo', 'bar'], $config->neighbours()->current()->tags()->toPrimitive()); + $this->assertSame(['foo', 'bar'], unwrap(first($config->neighbours())->tags())); $this->assertCount(1, $config->exports()); - $this->assertSame('echo "ENV=value"', $config->exports()->current()); + $this->assertSame('echo "ENV=value"', first($config->exports())); $this->assertCount(1, $config->actions()); - $this->assertSame('some bash command', $config->actions()->current()); + $this->assertSame('some bash command', first($config->actions())); } } diff --git a/tests/ConfigurationTest.php b/tests/ConfigurationTest.php index f91db13..486a5b5 100644 --- a/tests/ConfigurationTest.php +++ b/tests/ConfigurationTest.php @@ -9,7 +9,6 @@ Neighbour, EnvironmentVariable, }; -use Innmind\Url\PathInterface; use Innmind\Immutable\Set; use PHPUnit\Framework\TestCase; @@ -31,7 +30,7 @@ public function testInterface() public function testThrowWhenInvalidNeighbour() { $this->expectException(\TypeError::class); - $this->expectExceptionMessage('Argument 1 must be of type SetInterface'); + $this->expectExceptionMessage('Argument 1 must be of type Set'); new Configuration( Set::of('int'), @@ -43,7 +42,7 @@ public function testThrowWhenInvalidNeighbour() public function testThrowWhenInvalidEnvVars() { $this->expectException(\TypeError::class); - $this->expectExceptionMessage('Argument 2 must be of type SetInterface'); + $this->expectExceptionMessage('Argument 2 must be of type Set'); new Configuration( Set::of(Neighbour::class), @@ -55,7 +54,7 @@ public function testThrowWhenInvalidEnvVars() public function testThrowWhenInvalidActions() { $this->expectException(\TypeError::class); - $this->expectExceptionMessage('Argument 3 must be of type SetInterface'); + $this->expectExceptionMessage('Argument 3 must be of type Set'); new Configuration( Set::of(Neighbour::class), diff --git a/tests/Listener/PingTest.php b/tests/Listener/PingTest.php index a51d8cf..5c81b48 100644 --- a/tests/Listener/PingTest.php +++ b/tests/Listener/PingTest.php @@ -16,7 +16,7 @@ Server\Processes, }; use Innmind\Socket\{ - Event\DataReceived, + Event\ConnectionReady, Server\Connection, }; use Innmind\Url\Url; @@ -34,10 +34,13 @@ class PingTest extends TestCase */ public function testDoesNothingWhenInvalidPayload($payload) { - $event = new DataReceived( - $this->createMock(Connection::class), - Str::of(Json::encode($payload)) + $event = new ConnectionReady( + $connection = $this->createMock(Connection::class), ); + $connection + ->expects($this->once()) + ->method('read') + ->willReturn(Str::of(Json::encode($payload))); $server = $this->createMock(Server::class); $server ->expects($this->once()) @@ -63,10 +66,13 @@ public function testDoesNothingWhenInvalidPayload($payload) public function testRun() { - $event = new DataReceived( - $this->createMock(Connection::class), - Str::of(Json::encode(['tags' => ['foo', 'bar']])) + $event = new ConnectionReady( + $connection = $this->createMock(Connection::class), ); + $connection + ->expects($this->once()) + ->method('read') + ->willReturn(Str::of(Json::encode(['tags' => ['foo', 'bar']]))); $ping = new Ping( new Run( $this->createMock(Server::class), @@ -75,7 +81,7 @@ public function testRun() Neighbour::class, $expected = new Neighbour( new Name('watev'), - Url::fromString('example.com'), + Url::of('example.com'), 'foo' ) ), diff --git a/tests/NeighbourTest.php b/tests/NeighbourTest.php index 42b191b..2c41602 100644 --- a/tests/NeighbourTest.php +++ b/tests/NeighbourTest.php @@ -7,8 +7,9 @@ Neighbour, Neighbour\Name, }; -use Innmind\Url\UrlInterface; -use Innmind\Immutable\SetInterface; +use Innmind\Url\Url; +use Innmind\Immutable\Set; +use function Innmind\Immutable\unwrap; use PHPUnit\Framework\TestCase; class NeighbourTest extends TestCase @@ -17,16 +18,16 @@ public function testInterface() { $neighbour = new Neighbour( $name = new Name('foo'), - $url = $this->createMock(UrlInterface::class), + $url = Url::of('example.com'), 'bar', 'baz' ); $this->assertSame($name, $neighbour->name()); $this->assertSame($url, $neighbour->url()); - $this->assertInstanceOf(SetInterface::class, $neighbour->tags()); + $this->assertInstanceOf(Set::class, $neighbour->tags()); $this->assertSame('string', (string) $neighbour->tags()->type()); - $this->assertSame(['bar', 'baz'], $neighbour->tags()->toPrimitive()); + $this->assertSame(['bar', 'baz'], unwrap($neighbour->tags())); $this->assertTrue($neighbour->matches('bar')); $this->assertTrue($neighbour->matches('baz')); $this->assertTrue($neighbour->matches('bar', 'baz')); diff --git a/tests/Ping/DelegateTest.php b/tests/Ping/DelegateTest.php index 6c13f4f..ebc0988 100644 --- a/tests/Ping/DelegateTest.php +++ b/tests/Ping/DelegateTest.php @@ -21,7 +21,7 @@ public function testInterface() $this->assertInstanceOf( Ping::class, new Delegate( - new Map('string', Ping::class) + Map::of('string', Ping::class) ) ); } @@ -29,28 +29,28 @@ public function testInterface() public function testThrowWhenInvalidPingKey() { $this->expectException(\TypeError::class); - $this->expectExceptionMessage('Argument 1 must be of type MapInterface'); + $this->expectExceptionMessage('Argument 1 must be of type Map'); - new Delegate(new Map('int', Ping::class)); + new Delegate(Map::of('int', Ping::class)); } public function testThrowWhenInvalidPingValue() { $this->expectException(\TypeError::class); - $this->expectExceptionMessage('Argument 1 must be of type MapInterface'); + $this->expectExceptionMessage('Argument 1 must be of type Map'); - new Delegate(new Map('string', 'callable')); + new Delegate(Map::of('string', 'callable')); } public function testInvoke() { $neighbour = new Neighbour( new Name('foo'), - Url::fromString('tcp://host.com') + Url::of('tcp://host.com') ); $tags = ['foo', 'bar']; $ping = new Delegate( - (new Map('string', Ping::class)) + (Map::of('string', Ping::class)) ->put('ssh', $mock1 = $this->createMock(Ping::class)) ->put('tcp', $mock2 = $this->createMock(Ping::class)) ); @@ -70,11 +70,11 @@ public function testThrowWhenSchemeNotSupported() $this->expectException(SchemeNotSupported::class); $this->expectExceptionMessage('tcp'); - $ping = new Delegate(new Map('string', Ping::class)); + $ping = new Delegate(Map::of('string', Ping::class)); $ping(new Neighbour( new Name('foo'), - Url::fromString('tcp://example.com') + Url::of('tcp://example.com') )); } } diff --git a/tests/Ping/SshTest.php b/tests/Ping/SshTest.php index 9b980fb..f0a8535 100644 --- a/tests/Ping/SshTest.php +++ b/tests/Ping/SshTest.php @@ -31,7 +31,7 @@ public function testInvoke() { $neighbour = new Neighbour( new Name('foo'), - Url::fromString('ssh://baptouuuu@example.com:1337/path/to/config') + Url::of('ssh://baptouuuu@example.com:1337/path/to/config') ); $ping = new Ssh( @@ -50,8 +50,8 @@ public function testInvoke() ->expects($this->once()) ->method('execute') ->with($this->callback(static function($command): bool { - return (string) $command === "tower 'trigger' '--tags=foo,bar'" - && $command->workingDirectory() === '/path/to/config'; + return $command->toString() === "tower 'trigger' '--tags=foo,bar'" + && $command->workingDirectory()->toString() === '/path/to/config'; })); $this->assertNull($ping($neighbour, 'foo', 'bar')); diff --git a/tests/Ping/TcpTest.php b/tests/Ping/TcpTest.php index a458d90..0aa4c4b 100644 --- a/tests/Ping/TcpTest.php +++ b/tests/Ping/TcpTest.php @@ -29,7 +29,7 @@ public function testInvoke() { $neighbour = new Neighbour( new Name('foo'), - Url::fromString('tcp://127.0.0.1:1338') + Url::of('tcp://127.0.0.1:1338') ); $ping = new Tcp( $remote = $this->createMock(Remote::class) diff --git a/tests/RunTest.php b/tests/RunTest.php index 573bb68..8ca01f7 100644 --- a/tests/RunTest.php +++ b/tests/RunTest.php @@ -44,54 +44,51 @@ public function testInvoke() ->expects($this->at(0)) ->method('execute') ->with($this->callback(static function($command): bool { - return (string) $command === 'env1'; + return $command->toString() === 'env1'; })) ->willReturn($process = $this->createMock(Process::class)); $process ->expects($this->once()) - ->method('wait') - ->will($this->returnSelf()); + ->method('wait'); $process ->expects($this->once()) ->method('output') ->willReturn($output = $this->createMock(Output::class)); $output ->expects($this->once()) - ->method('__toString') + ->method('toString') ->willReturn("ENV1=foo\n"); $processes ->expects($this->at(1)) ->method('execute') ->with($this->callback(static function($command): bool { - return (string) $command === 'env2' && + return $command->toString() === 'env2' && $command->environment()->get('ENV1') === 'foo'; })) ->willReturn($process = $this->createMock(Process::class)); $process ->expects($this->once()) - ->method('wait') - ->will($this->returnSelf()); + ->method('wait'); $process ->expects($this->once()) ->method('output') ->willReturn($output = $this->createMock(Output::class)); $output ->expects($this->once()) - ->method('__toString') + ->method('toString') ->willReturn("ENV2=bar\n"); $processes ->expects($this->at(2)) ->method('execute') ->with($this->callback(static function($command): bool { - return (string) $command === 'action1' && + return $command->toString() === 'action1' && $command->environment()->get('ENV1') === 'foo' && $command->environment()->get('ENV2') === 'bar'; })) ->willReturn($process = $this->createMock(Process::class)); $process ->expects($this->once()) - ->method('wait') - ->will($this->returnSelf()); + ->method('wait'); $process ->expects($this->once()) ->method('exitCode') @@ -100,15 +97,14 @@ public function testInvoke() ->expects($this->at(3)) ->method('execute') ->with($this->callback(static function($command): bool { - return (string) $command === 'action2' && + return $command->toString() === 'action2' && $command->environment()->get('ENV1') === 'foo' && $command->environment()->get('ENV2') === 'bar'; })) ->willReturn($process = $this->createMock(Process::class)); $process ->expects($this->once()) - ->method('wait') - ->will($this->returnSelf()); + ->method('wait'); $process ->expects($this->once()) ->method('exitCode') @@ -141,13 +137,12 @@ public function testThrowWhenActionFailed() ->expects($this->once()) ->method('execute') ->with($this->callback(static function($command): bool { - return (string) $command === 'action'; + return $command->toString() === 'action'; })) ->willReturn($process = $this->createMock(Process::class)); $process ->expects($this->once()) - ->method('wait') - ->will($this->returnSelf()); + ->method('wait'); $process ->expects($this->once()) ->method('exitCode') @@ -165,17 +160,17 @@ public function testPingNeighbours() ->willReturn($processes = $this->createMock(Processes::class)); $neighbour1 = new Neighbour( new Name('1'), - Url::fromString('example.com'), + Url::of('example.com'), 'foo' ); $neighbour2 = new Neighbour( new Name('2'), - Url::fromString('example.com'), + Url::of('example.com'), 'bar' ); $neighbour3 = new Neighbour( new Name('3'), - Url::fromString('example.com'), + Url::of('example.com'), 'baz' ); $run = new Run( diff --git a/tower b/tower index a2359cd..43a35a2 100755 --- a/tower +++ b/tower @@ -30,15 +30,19 @@ use function Innmind\SilentCartographer\bootstrap as cartographer; new class extends Main { protected function main(Environment $env, OperatingSystem $os): void { - $os = cartographer($os)['cli'](Url::fromString(__DIR__)); - $path = new Path( - $env->variables()['TOWER_CONFIG'] ?? $env->workingDirectory().'/tower.yml' - ); + $os = cartographer($os)['cli'](Url::of(__DIR__)); + + $path = $env->workingDirectory()->resolve(Path::of('tower.yml')); + + if ($env->variables()->contains('TOWER_CONFIG')) { + $path = Path::of($env->variables()->get('TOWER_CONFIG')); + } $run = bootstrap( $os->control(), $os->remote(), $os->ports(), + $os->sockets(), $path ); $run($env); From e2629d7238d554962f0a83739c016bdd9c27b48b Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sat, 28 Mar 2020 15:38:24 +0100 Subject: [PATCH 4/9] add psalm --- composer.json | 3 ++- psalm.xml | 16 ++++++++++++++++ src/Command/Ping.php | 6 +++--- src/Command/Trigger.php | 6 +++--- src/Configuration.php | 8 ++++++++ src/Configuration/Schema.php | 4 ++++ src/Configuration/Yaml.php | 2 ++ src/Listener/Ping.php | 2 ++ src/Neighbour.php | 3 ++- src/Ping/Delegate.php | 4 ++++ src/Run.php | 1 + src/bootstrap.php | 8 ++++++++ 12 files changed, 55 insertions(+), 8 deletions(-) create mode 100644 psalm.xml diff --git a/composer.json b/composer.json index 4644be7..60f4283 100644 --- a/composer.json +++ b/composer.json @@ -39,7 +39,8 @@ }, "require-dev": { "phpunit/phpunit": "~8.0", - "giorgiosironi/eris": "^0.11.0" + "giorgiosironi/eris": "^0.11.0", + "vimeo/psalm": "^3.10" }, "bin": ["tower"], "extra": { diff --git a/psalm.xml b/psalm.xml new file mode 100644 index 0000000..617f63d --- /dev/null +++ b/psalm.xml @@ -0,0 +1,16 @@ + + + + + + + + + diff --git a/src/Command/Ping.php b/src/Command/Ping.php index c89b51c..03450da 100644 --- a/src/Command/Ping.php +++ b/src/Command/Ping.php @@ -47,17 +47,17 @@ public function __invoke(Environment $env, Arguments $arguments, Options $option $tags = []; if ($options->contains('tags')) { - $tags = Str::of($options->get('tags')) + $tags = unwrap(Str::of($options->get('tags')) ->split(',') ->reduce( Set::of('string'), static function(Set $tags, Str $tag): Set { return $tags->add($tag->trim()->toString()); } - ); + )); } - ($this->ping)($neighbour, ...unwrap($tags)); + ($this->ping)($neighbour, ...$tags); } public function toString(): string diff --git a/src/Command/Trigger.php b/src/Command/Trigger.php index a201c96..f9b2b83 100644 --- a/src/Command/Trigger.php +++ b/src/Command/Trigger.php @@ -30,17 +30,17 @@ public function __invoke(Environment $env, Arguments $arguments, Options $option $tags = []; if ($options->contains('tags')) { - $tags = Str::of($options->get('tags')) + $tags = unwrap(Str::of($options->get('tags')) ->split(',') ->reduce( Set::of('string'), static function(Set $tags, Str $tag): Set { return $tags->add($tag->trim()->toString()); } - ); + )); } - ($this->run)(...unwrap($tags)); + ($this->run)(...$tags); } public function toString(): string diff --git a/src/Configuration.php b/src/Configuration.php index cc31c9e..98e6264 100644 --- a/src/Configuration.php +++ b/src/Configuration.php @@ -8,10 +8,18 @@ final class Configuration { + /** @var Set */ private Set $neighbours; + /** @var Set */ private Set $exports; + /** @var Set */ private Set $actions; + /** + * @param Set $neighbours + * @param Set $exports + * @param Set $actions + */ public function __construct( Set $neighbours, Set $exports, diff --git a/src/Configuration/Schema.php b/src/Configuration/Schema.php index 3f51c48..7e197d9 100644 --- a/src/Configuration/Schema.php +++ b/src/Configuration/Schema.php @@ -15,6 +15,10 @@ public function getConfigTreeBuilder() $builder = new TreeBuilder('tower'); $root = $builder->getRootNode(); + /** + * @psalm-suppress MixedMethodCall + * @psalm-suppress PossiblyUndefinedMethod + */ $root ->children() ->arrayNode('exports') diff --git a/src/Configuration/Yaml.php b/src/Configuration/Yaml.php index 2a94edd..4a3b4de 100644 --- a/src/Configuration/Yaml.php +++ b/src/Configuration/Yaml.php @@ -29,10 +29,12 @@ public function __construct() public function __invoke(Path $configPath): Configuration { + /** @var array{neighbours: array}>, exports: list, actions: list} */ $config = $this->processor->processConfiguration( $this->config, [Parser::parseFile($configPath->toString())] ); + /** @var Set */ $neighbours = Set::of(Neighbour::class); foreach ($config['neighbours'] as $name => $value) { diff --git a/src/Listener/Ping.php b/src/Listener/Ping.php index fbbb76a..0100707 100644 --- a/src/Listener/Ping.php +++ b/src/Listener/Ping.php @@ -18,6 +18,7 @@ public function __construct(Run $run) public function __invoke(ConnectionReady $event): void { + /** @var array{tags?: list}|mixed */ $payload = Json::decode($event->connection()->read()->toString()); if (!\is_array($payload)) { @@ -32,6 +33,7 @@ public function __invoke(ConnectionReady $event): void return; } + /** @psalm-suppress MixedArgument */ ($this->run)(...$payload['tags']); } } diff --git a/src/Neighbour.php b/src/Neighbour.php index ea84dd6..516084f 100644 --- a/src/Neighbour.php +++ b/src/Neighbour.php @@ -11,13 +11,14 @@ final class Neighbour { private Name $name; private Url $url; + /** @var Set */ private Set $tags; public function __construct(Name $name, Url $url, string ...$tags) { $this->name = $name; $this->url = $url; - $this->tags = Set::of('string', ...$tags); + $this->tags = Set::strings(...$tags); } public function name(): Name diff --git a/src/Ping/Delegate.php b/src/Ping/Delegate.php index 7a7ed67..77dbf27 100644 --- a/src/Ping/Delegate.php +++ b/src/Ping/Delegate.php @@ -12,8 +12,12 @@ final class Delegate implements Ping { + /** @var Map */ private Map $pings; + /** + * @param Map $pings + */ public function __construct(Map $pings) { if ( diff --git a/src/Run.php b/src/Run.php index c509585..509920e 100644 --- a/src/Run.php +++ b/src/Run.php @@ -68,6 +68,7 @@ static function(Command $command, EnvironmentVariable $env): Command { */ private function envs(): Set { + /** @var Set */ return $this->configuration->exports()->reduce( Set::of(EnvironmentVariable::class), function(Set $envs, string $command): Set { diff --git a/src/bootstrap.php b/src/bootstrap.php index 736249e..b51b596 100644 --- a/src/bootstrap.php +++ b/src/bootstrap.php @@ -30,6 +30,10 @@ function bootstrap( Path $config ): Commands { $configuration = (new Configuration\Yaml)($config); + /** + * @psalm-suppress InvalidScalarArgument + * @psalm-suppress InvalidArgument + */ $ping = new Ping\Delegate( Map::of('string', Ping::class) ('tcp', new Ping\Tcp($remote)) @@ -37,6 +41,10 @@ function bootstrap( ); $run = new Run($server, $configuration, $ping); + /** + * @psalm-suppress InvalidScalarArgument + * @psalm-suppress InvalidArgument + */ $loop = new Serve( new EventBus\Map( Map::of('string', 'callable') From d10bec4513c837e7cf7b9d45d76b43d82e9008ce Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sat, 28 Mar 2020 15:44:00 +0100 Subject: [PATCH 5/9] CS --- src/Command/Listen.php | 4 ++-- src/Command/Trigger.php | 2 +- src/Configuration.php | 18 ++++-------------- src/Configuration/Yaml.php | 12 ++++++------ src/Neighbour.php | 6 +++--- src/Ping/Delegate.php | 11 ++--------- src/Ping/Ssh.php | 2 +- src/Ping/Tcp.php | 2 +- src/Run.php | 12 ++++++------ src/bootstrap.php | 6 +++--- 10 files changed, 29 insertions(+), 46 deletions(-) diff --git a/src/Command/Listen.php b/src/Command/Listen.php index 5077026..2b64e16 100644 --- a/src/Command/Listen.php +++ b/src/Command/Listen.php @@ -44,7 +44,7 @@ public function __invoke(Environment $env, Arguments $arguments, Options $option ServerCommand::background('tower') ->withArgument('listen') ->withArgument($arguments->get('port')) - ->withWorkingDirectory($env->workingDirectory()) + ->withWorkingDirectory($env->workingDirectory()), ); return; @@ -55,7 +55,7 @@ public function __invoke(Environment $env, Arguments $arguments, Options $option $socket = $this->ports->open( Transport::tcp(), IPv4::of('127.0.0.1'), - Port::of((int) $arguments->get('port')) + Port::of((int) $arguments->get('port')), ); ($this->serve)($socket); diff --git a/src/Command/Trigger.php b/src/Command/Trigger.php index f9b2b83..ae7a52a 100644 --- a/src/Command/Trigger.php +++ b/src/Command/Trigger.php @@ -36,7 +36,7 @@ public function __invoke(Environment $env, Arguments $arguments, Options $option Set::of('string'), static function(Set $tags, Str $tag): Set { return $tags->add($tag->trim()->toString()); - } + }, )); } diff --git a/src/Configuration.php b/src/Configuration.php index 98e6264..07092f6 100644 --- a/src/Configuration.php +++ b/src/Configuration.php @@ -5,6 +5,7 @@ use Innmind\Tower\Configuration\Loader; use Innmind\Immutable\Set; +use function Innmind\Immutable\assertSet; final class Configuration { @@ -25,20 +26,9 @@ public function __construct( Set $exports, Set $actions ) { - if ((string) $neighbours->type() !== Neighbour::class) { - throw new \TypeError(sprintf( - 'Argument 1 must be of type Set<%s>', - Neighbour::class - )); - } - - if ((string) $exports->type() !== 'string') { - throw new \TypeError('Argument 2 must be of type Set'); - } - - if ((string) $actions->type() !== 'string') { - throw new \TypeError('Argument 3 must be of type Set'); - } + assertSet(Neighbour::class, $neighbours, 1); + assertSet('string', $exports, 2); + assertSet('string', $actions, 3); $this->neighbours = $neighbours; $this->exports = $exports; diff --git a/src/Configuration/Yaml.php b/src/Configuration/Yaml.php index 4a3b4de..7fd3732 100644 --- a/src/Configuration/Yaml.php +++ b/src/Configuration/Yaml.php @@ -32,26 +32,26 @@ public function __invoke(Path $configPath): Configuration /** @var array{neighbours: array}>, exports: list, actions: list} */ $config = $this->processor->processConfiguration( $this->config, - [Parser::parseFile($configPath->toString())] + [Parser::parseFile($configPath->toString())], ); /** @var Set */ $neighbours = Set::of(Neighbour::class); foreach ($config['neighbours'] as $name => $value) { - $neighbours = $neighbours->add( + $neighbours = ($neighbours)( new Neighbour( new Name($name), Url::of($value['url']), - ...$value['tags'] - ) + ...$value['tags'], + ), ); } return new Configuration( $neighbours, - Set::of('string', ...$config['exports']), - Set::of('string', ...$config['actions']) + Set::strings(...$config['exports']), + Set::strings(...$config['actions']), ); } } diff --git a/src/Neighbour.php b/src/Neighbour.php index 516084f..1354ed8 100644 --- a/src/Neighbour.php +++ b/src/Neighbour.php @@ -41,12 +41,12 @@ public function tags(): Set public function matches(string ...$tags): bool { - $tags = Set::of('string', ...$tags); + $tags = Set::strings(...$tags); - if ($tags->size() === 0) { + if ($tags->empty()) { return true; } - return $this->tags->intersect($tags)->size() > 0; + return !$this->tags->intersect($tags)->empty(); } } diff --git a/src/Ping/Delegate.php b/src/Ping/Delegate.php index 77dbf27..84bd889 100644 --- a/src/Ping/Delegate.php +++ b/src/Ping/Delegate.php @@ -9,6 +9,7 @@ Exception\SchemeNotSupported, }; use Innmind\Immutable\Map; +use function Innmind\Immutable\assertMap; final class Delegate implements Ping { @@ -20,15 +21,7 @@ final class Delegate implements Ping */ public function __construct(Map $pings) { - if ( - (string) $pings->keyType() !== 'string' || - (string) $pings->valueType() !== Ping::class - ) { - throw new \TypeError(sprintf( - 'Argument 1 must be of type Map', - Ping::class - )); - } + assertMap('string', Ping::class, $pings, 1); $this->pings = $pings; } diff --git a/src/Ping/Ssh.php b/src/Ping/Ssh.php index 8a82a20..4b96d44 100644 --- a/src/Ping/Ssh.php +++ b/src/Ping/Ssh.php @@ -29,7 +29,7 @@ public function __invoke(Neighbour $neighbour, string ...$tags): void Command::background('tower') ->withArgument('trigger') ->withOption('tags', implode(',', $tags)) - ->withWorkingDirectory($neighbour->url()->path()) + ->withWorkingDirectory($neighbour->url()->path()), ); } } diff --git a/src/Ping/Tcp.php b/src/Ping/Tcp.php index 21542b2..992b339 100644 --- a/src/Ping/Tcp.php +++ b/src/Ping/Tcp.php @@ -25,7 +25,7 @@ public function __invoke(Neighbour $neighbour, string ...$tags): void { $socket = $this->remote->socket( Transport::tcp(), - $neighbour->url()->authority() + $neighbour->url()->authority(), ); $socket->write(Str::of(Json::encode([ 'tags' => $tags, diff --git a/src/Run.php b/src/Run.php index 509920e..b345052 100644 --- a/src/Run.php +++ b/src/Run.php @@ -41,9 +41,9 @@ public function __invoke(string ...$tags): void static function(Command $command, EnvironmentVariable $env): Command { return $command->withEnvironment( $env->name(), - $env->value() + $env->value(), ); - } + }, ); $process = $this->processes->execute($command); $process->wait(); @@ -77,18 +77,18 @@ function(Set $envs, string $command): Set { static function(Command $command, EnvironmentVariable $env): Command { return $command->withEnvironment( $env->name(), - $env->value() + $env->value(), ); - } + }, ); $process = $this->processes->execute($command); $process->wait(); $output = $process->output()->toString(); - return $envs->add(new EnvironmentVariable( + return ($envs)(new EnvironmentVariable( Str::of($output)->trim()->toString(), )); - } + }, ); } } diff --git a/src/bootstrap.php b/src/bootstrap.php index b51b596..2d900bd 100644 --- a/src/bootstrap.php +++ b/src/bootstrap.php @@ -37,7 +37,7 @@ function bootstrap( $ping = new Ping\Delegate( Map::of('string', Ping::class) ('tcp', new Ping\Tcp($remote)) - ('ssh', new Ping\Ssh($remote)) + ('ssh', new Ping\Ssh($remote)), ); $run = new Run($server, $configuration, $ping); @@ -48,7 +48,7 @@ function bootstrap( $loop = new Serve( new EventBus\Map( Map::of('string', 'callable') - (ConnectionReady::class, new Listener\Ping($run)) + (ConnectionReady::class, new Listener\Ping($run)), ), $sockets->watch(new ElapsedPeriod(3600000)), // 1 hour ); @@ -56,6 +56,6 @@ function bootstrap( return new Commands( new Command\Trigger($run), new Command\Ping($configuration, $ping), - new Command\Listen($ports, $server, $loop) + new Command\Listen($ports, $server, $loop), ); } From b4b145e741ead94f9e350cb14a53112eba53c56c Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sat, 28 Mar 2020 15:48:11 +0100 Subject: [PATCH 6/9] use pack arguments instead of an option to simplify the code --- src/Command/Ping.php | 17 ++--------------- src/Command/Trigger.php | 17 ++--------------- tests/Command/PingTest.php | 11 +++++------ tests/Command/TriggerTest.php | 13 +++++++------ 4 files changed, 16 insertions(+), 42 deletions(-) diff --git a/src/Command/Ping.php b/src/Command/Ping.php index 03450da..d667dc0 100644 --- a/src/Command/Ping.php +++ b/src/Command/Ping.php @@ -44,26 +44,13 @@ public function __invoke(Environment $env, Arguments $arguments, Options $option return (string) $neighbour->name() === $name; })); - $tags = []; - - if ($options->contains('tags')) { - $tags = unwrap(Str::of($options->get('tags')) - ->split(',') - ->reduce( - Set::of('string'), - static function(Set $tags, Str $tag): Set { - return $tags->add($tag->trim()->toString()); - } - )); - } - - ($this->ping)($neighbour, ...$tags); + ($this->ping)($neighbour, ...unwrap($arguments->pack())); } public function toString(): string { return <<contains('tags')) { - $tags = unwrap(Str::of($options->get('tags')) - ->split(',') - ->reduce( - Set::of('string'), - static function(Set $tags, Str $tag): Set { - return $tags->add($tag->trim()->toString()); - }, - )); - } - - ($this->run)(...$tags); + ($this->run)(...unwrap($arguments->pack())); } public function toString(): string { return <<createMock(Environment::class), new Arguments( Map::of('string', 'string') - ('server', 'bar') + ('server', 'bar'), + Sequence::strings('foobar', 'baz'), ), - new Options( - Map::of('string', 'string') - ('tags', 'foobar , baz') - ) + new Options, )); } public function testUsage() { $expected = <<assertNull($trigger( $this->createMock(Environment::class), - new Arguments, - new Options( - Map::of('string', 'string') - ('tags', 'foo , bar') - ) + new Arguments( + null, + Sequence::strings('foo', 'bar'), + ), + new Options, )); } public function testUsage() { $expected = << Date: Sat, 28 Mar 2020 15:49:54 +0100 Subject: [PATCH 7/9] rename __toString to toString --- src/Command/Ping.php | 2 +- src/Neighbour/Name.php | 2 +- tests/Configuration/YamlTest.php | 2 +- tests/Neighbour/NameTest.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Command/Ping.php b/src/Command/Ping.php index d667dc0..5402097 100644 --- a/src/Command/Ping.php +++ b/src/Command/Ping.php @@ -41,7 +41,7 @@ public function __invoke(Environment $env, Arguments $arguments, Options $option ->configuration ->neighbours() ->filter(static function(Neighbour $neighbour) use ($name): bool { - return (string) $neighbour->name() === $name; + return $neighbour->name()->toString() === $name; })); ($this->ping)($neighbour, ...unwrap($arguments->pack())); diff --git a/src/Neighbour/Name.php b/src/Neighbour/Name.php index d0028dc..f17eb81 100644 --- a/src/Neighbour/Name.php +++ b/src/Neighbour/Name.php @@ -19,7 +19,7 @@ public function __construct(string $value) $this->value = $value; } - public function __toString(): string + public function toString(): string { return $this->value; } diff --git a/tests/Configuration/YamlTest.php b/tests/Configuration/YamlTest.php index 0ea3c9b..918de63 100644 --- a/tests/Configuration/YamlTest.php +++ b/tests/Configuration/YamlTest.php @@ -30,7 +30,7 @@ public function testInvoke() $this->assertCount(1, $config->neighbours()); $this->assertSame( '_name_', - (string) first($config->neighbours())->name() + first($config->neighbours())->name()->toString() ); $this->assertSame( 'ssh://example.com:80/path/to/config/on/neighbour/server.yml', diff --git a/tests/Neighbour/NameTest.php b/tests/Neighbour/NameTest.php index 97ee6aa..adb7ca5 100644 --- a/tests/Neighbour/NameTest.php +++ b/tests/Neighbour/NameTest.php @@ -25,7 +25,7 @@ public function testInterface() return $string !== ''; }) ->then(function(string $string): void { - $this->assertSame($string, (string) new Name($string)); + $this->assertSame($string, (new Name($string))->toString()); }); } From ead03fb8019cd234e002e5e79931f2a869f37191 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sat, 28 Mar 2020 15:50:28 +0100 Subject: [PATCH 8/9] CS --- tower | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tower b/tower index 43a35a2..4318262 100755 --- a/tower +++ b/tower @@ -43,7 +43,7 @@ new class extends Main { $os->remote(), $os->ports(), $os->sockets(), - $path + $path, ); $run($env); } From 3d5f463fe9fd0a2831e12315c1eb77ecc4637d80 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sat, 28 Mar 2020 15:51:32 +0100 Subject: [PATCH 9/9] replace travis by github ci --- .gitattributes | 3 -- .github/workflows/ci.yml | 65 ++++++++++++++++++++++++++++++++++++++++ .scrutinizer.yml | 6 ---- .travis.yml | 14 --------- README.md | 8 ++--- 5 files changed, 68 insertions(+), 28 deletions(-) create mode 100644 .github/workflows/ci.yml delete mode 100644 .scrutinizer.yml delete mode 100644 .travis.yml diff --git a/.gitattributes b/.gitattributes index 27d7dee..4160131 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,7 +1,4 @@ /.gitattributes export-ignore /.gitignore export-ignore -/.scrutinizer.yml export-ignore -/.travis.yml export-ignore /phpunit.xml.dist export-ignore -/fixtures export-ignore /tests export-ignore diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..8be1427 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,65 @@ +name: CI + +on: [push] + +jobs: + phpunit: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macOS-latest] + php-version: ['7.4'] + name: 'PHPUnit - PHP/${{ matrix.php-version }} - OS/${{ matrix.os }}' + steps: + - name: Checkout + uses: actions/checkout@v1 + - name: Setup PHP + uses: shivammathur/setup-php@v1 + with: + php-version: ${{ matrix.php-version }} + extensions: mbstring, intl + coverage: xdebug + ini-values: xdebug.max_nesting_level=2048 + - name: Get Composer Cache Directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + - name: Cache dependencies + uses: actions/cache@v1 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-composer- + - name: Install Dependencies + run: composer install --no-progress + - name: PHPUnit + run: vendor/bin/phpunit --coverage-clover=coverage.clover + - uses: codecov/codecov-action@v1 + with: + token: ${{ secrets.CODECOV_TOKEN }} + psalm: + runs-on: ubuntu-latest + strategy: + matrix: + php-version: ['7.4'] + name: 'Psalm - PHP/${{ matrix.php-version }}' + steps: + - name: Checkout + uses: actions/checkout@v1 + - name: Setup PHP + uses: shivammathur/setup-php@v1 + with: + php-version: ${{ matrix.php-version }} + extensions: mbstring, intl + - name: Get Composer Cache Directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + - name: Cache dependencies + uses: actions/cache@v1 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-composer- + - name: Install Dependencies + run: composer install --no-progress + - name: Psalm + run: vendor/bin/psalm --shepherd diff --git a/.scrutinizer.yml b/.scrutinizer.yml deleted file mode 100644 index 912be99..0000000 --- a/.scrutinizer.yml +++ /dev/null @@ -1,6 +0,0 @@ -tools: - external_code_coverage: - runs: 2 -filter: - excluded_paths: - - tests/* diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 6319ecd..0000000 --- a/.travis.yml +++ /dev/null @@ -1,14 +0,0 @@ -language: php -php: - - 7.2 - - 7.3 - - '7.4snapshot' - - nightly -matrix: - allow_failures: - - php: nightly -before_script: composer install -script: vendor/bin/phpunit --coverage-clover=coverage.clover -after_script: - - if [ "$TRAVIS_PHP_VERSION" != "nightly" ] && [ "$TRAVIS_PHP_VERSION" != "7.4snapshot" ]; then wget https://scrutinizer-ci.com/ocular.phar; fi - - if [ "$TRAVIS_PHP_VERSION" != "nightly" ] && [ "$TRAVIS_PHP_VERSION" != "7.4snapshot" ]; then php ocular.phar code-coverage:upload --format=php-clover coverage.clover; fi diff --git a/README.md b/README.md index bb669e8..1845852 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,8 @@ # Tower -| `master` | `develop` | -|----------|-----------| -| [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/Innmind/Tower/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/Innmind/Tower/?branch=master) | [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/Innmind/Tower/badges/quality-score.png?b=develop)](https://scrutinizer-ci.com/g/Innmind/Tower/?branch=develop) | -| [![Code Coverage](https://scrutinizer-ci.com/g/Innmind/Tower/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/Innmind/Tower/?branch=master) | [![Code Coverage](https://scrutinizer-ci.com/g/Innmind/Tower/badges/coverage.png?b=develop)](https://scrutinizer-ci.com/g/Innmind/Tower/?branch=develop) | -| [![Build Status](https://scrutinizer-ci.com/g/Innmind/Tower/badges/build.png?b=master)](https://scrutinizer-ci.com/g/Innmind/Tower/build-status/master) | [![Build Status](https://scrutinizer-ci.com/g/Innmind/Tower/badges/build.png?b=develop)](https://scrutinizer-ci.com/g/Innmind/Tower/build-status/develop) | +[![Build Status](https://github.com/Innmind/Tower/workflows/CI/badge.svg)](https://github.com/Innmind/Tower/actions?query=workflow%3ACI) +[![codecov](https://codecov.io/gh/Innmind/Tower/branch/develop/graph/badge.svg)](https://codecov.io/gh/Innmind/Tower) +[![Type Coverage](https://shepherd.dev/github/Innmind/Tower/coverage.svg)](https://shepherd.dev/github/Innmind/Tower) This is a command line tool to deploy your code base with a new approach. Instead of building another tool sending a set of shell commands over ssh with a logic of point to point, Tower takes the approach of servers as nodes of a tree where from a node you trigger the _tower_ of sub-nodes.