Skip to content

Commit

Permalink
Enable tool exclusion by tags
Browse files Browse the repository at this point in the history
  • Loading branch information
jakzal committed Dec 31, 2018
1 parent 6ee5ca4 commit 221c2f6
Show file tree
Hide file tree
Showing 20 changed files with 290 additions and 54 deletions.
35 changes: 34 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,14 @@ curl -s https://api.github.com/repos/jakzal/toolbox/releases/latest \
./toolbox list-tools
```

#### Exclude tools by tags

To exclude some tools from the listing, multiple `--exclude-tag` options can be added:

```
bin/toolbox.php list-tools --exclude-tag ~php7.3 --exclude-tag foo
```

### Install tools

```
Expand Down Expand Up @@ -117,6 +125,14 @@ To only see what commands would be executed, use the dry run mode:
./toolbox install --dry-run
```

#### Exclude tools by tags

To exclude some tools from installation, multiple `--exclude-tag` options can be added:

```
bin/toolbox.php install --exclude-tag ~php7.3 --exclude-tag foo
```

### Test if installed tools are usable

```
Expand All @@ -131,6 +147,14 @@ To only see what commands would be executed, use the dry run mode:
./toolbox test --dry-run
```

#### Exclude tools by tags

To exclude some tools from the generated test command, multiple `--exclude-tag` options can be added:

```
bin/toolbox.php test --exclude-tag ~php7.3 --exclude-tag foo
```

### Tools definitions

By default `resources/pre-installation.json` and `resources/tools.json` are used to load tool definitions.
Expand All @@ -144,4 +168,13 @@ Tool definition location(s) can be also specified with the `TOOLBOX_JSON` enviro

```
TOOLBOX_JSON='path/to/file1.json,path/to/file2.json' ./toolbox list-tools
```
```

### Tool tags

Tools can be tagged in order to enable grouping and filtering them.

The tags below have a special meaning:

* `pre-installation` - these tools will be installed before any other tools.
* `~php7.3`, `~php7.1` etc - used to exclude installation on the specified php version.
3 changes: 2 additions & 1 deletion resources/tools.json
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,8 @@
"bin": "%target-dir%/php-cs-fixer"
}
},
"test": "php-cs-fixer list"
"test": "php-cs-fixer list",
"tags": ["~php7.3"]
},
{
"name": "php-formatter",
Expand Down
4 changes: 3 additions & 1 deletion src/Cli/Command/InstallCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Zalas\Toolbox\Runner\Runner;
use Zalas\Toolbox\Tool\Filter;
use Zalas\Toolbox\UseCase\InstallTools;

final class InstallCommand extends Command
Expand All @@ -31,10 +32,11 @@ protected function configure()
$this->setDescription('Installs tools');
$this->addOption('dry-run', null, InputOption::VALUE_NONE, 'Output the command without executing it');
$this->addOption('target-dir', null, InputOption::VALUE_REQUIRED, 'The target installation directory', $this->defaultTargetDir());
$this->addOption('exclude-tag', 'e', InputOption::VALUE_REQUIRED|InputOption::VALUE_IS_ARRAY, 'Tool tags to exclude');
}

protected function execute(InputInterface $input, OutputInterface $output)
{
return $this->runner->run(\call_user_func($this->useCase));
return $this->runner->run(\call_user_func($this->useCase, new Filter($input->getOption('exclude-tag'))));
}
}
5 changes: 4 additions & 1 deletion src/Cli/Command/ListCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\StyleInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Zalas\Toolbox\Tool\Filter;
use Zalas\Toolbox\Tool\Tool;
use Zalas\Toolbox\UseCase\ListTools;

Expand All @@ -26,11 +28,12 @@ public function __construct(ListTools $listTools)
protected function configure()
{
$this->setDescription('Lists available tools');
$this->addOption('exclude-tag', 'e', InputOption::VALUE_REQUIRED|InputOption::VALUE_IS_ARRAY, 'Tool tags to exclude');
}

protected function execute(InputInterface $input, OutputInterface $output)
{
$tools = \call_user_func($this->listTools);
$tools = \call_user_func($this->listTools, new Filter($input->getOption('exclude-tag')));

$style = $this->createStyle($input, $output);
$style->title('Available tools');
Expand Down
4 changes: 3 additions & 1 deletion src/Cli/Command/TestCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Zalas\Toolbox\Runner\Runner;
use Zalas\Toolbox\Tool\Filter;
use Zalas\Toolbox\UseCase\TestTools;

final class TestCommand extends Command
Expand All @@ -31,10 +32,11 @@ protected function configure()
$this->setDescription('Runs basic tests to verify tools are installed');
$this->addOption('dry-run', null, InputOption::VALUE_NONE, 'Output the command without executing it');
$this->addOption('target-dir', null, InputOption::VALUE_REQUIRED, 'The target installation directory', $this->defaultTargetDir());
$this->addOption('exclude-tag', 'e', InputOption::VALUE_REQUIRED|InputOption::VALUE_IS_ARRAY, 'Tool tags to exclude');
}

protected function execute(InputInterface $input, OutputInterface $output)
{
return $this->runner->run(\call_user_func($this->useCase));
return $this->runner->run(\call_user_func($this->useCase, new Filter($input->getOption('exclude-tag'))));
}
}
8 changes: 7 additions & 1 deletion src/Json/JsonTools.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use RuntimeException;
use Zalas\Toolbox\Json\Factory\ToolFactory;
use Zalas\Toolbox\Tool\Collection;
use Zalas\Toolbox\Tool\Filter;
use Zalas\Toolbox\Tool\Tool;
use Zalas\Toolbox\Tool\Tools;

Expand All @@ -24,7 +25,12 @@ public function __construct(callable $resourceLocator)
/**
* @return Collection|Tool[]
*/
public function all(): Collection
public function all(Filter $filter): Collection
{
return $this->loadTools()->filter($filter);
}

private function loadTools(): Collection
{
return \array_reduce($this->resources(), function (Collection $tools, string $resource): Collection {
return $tools->merge(Collection::create(
Expand Down
24 changes: 24 additions & 0 deletions src/Tool/Filter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php declare(strict_types=1);

namespace Zalas\Toolbox\Tool;

class Filter
{
/**
* @var string[]
*/
private $excludedTags;

/**
* @param string[] $excludedTags
*/
public function __construct(array $excludedTags)
{
$this->excludedTags = $excludedTags;
}

public function __invoke(Tool $tool): bool
{
return $this->excludedTags === \array_diff($this->excludedTags, $tool->tags());
}
}
2 changes: 1 addition & 1 deletion src/Tool/Tools.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ interface Tools
* @return Collection|Tool[]
* @throws RuntimeException in case tools cannot be loaded
*/
public function all(): Collection;
public function all(Filter $filter): Collection;
}
5 changes: 3 additions & 2 deletions src/UseCase/InstallTools.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use Zalas\Toolbox\Tool\Command\OptimisedComposerBinPluginCommand;
use Zalas\Toolbox\Tool\Command\PharDownloadCommand;
use Zalas\Toolbox\Tool\Command\ShCommand;
use Zalas\Toolbox\Tool\Filter;
use Zalas\Toolbox\Tool\Tool;
use Zalas\Toolbox\Tool\Tools;

Expand All @@ -28,9 +29,9 @@ public function __construct(Tools $tools)
$this->tools = $tools;
}

public function __invoke(): Command
public function __invoke(Filter $filter): Command
{
$tools = $this->tools->all();
$tools = $this->tools->all($filter);
$installationCommands = $this->installationCommands($tools);
$commandFilter = $this->commandFilter($this->toolCommands($tools));

Expand Down
5 changes: 3 additions & 2 deletions src/UseCase/ListTools.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Zalas\Toolbox\UseCase;

use Zalas\Toolbox\Tool\Collection;
use Zalas\Toolbox\Tool\Filter;
use Zalas\Toolbox\Tool\Tool;
use Zalas\Toolbox\Tool\Tools;

Expand All @@ -21,8 +22,8 @@ public function __construct(Tools $tools)
/**
* @return Collection|Tool[]
*/
public function __invoke(): Collection
public function __invoke(Filter $filter): Collection
{
return $this->tools->all();
return $this->tools->all($filter);
}
}
5 changes: 3 additions & 2 deletions src/UseCase/TestTools.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Zalas\Toolbox\Tool\Command;
use Zalas\Toolbox\Tool\Command\MultiStepCommand;
use Zalas\Toolbox\Tool\Filter;
use Zalas\Toolbox\Tool\Tool;
use Zalas\Toolbox\Tool\Tools;

Expand All @@ -16,10 +17,10 @@ public function __construct(Tools $tools)
$this->tools = $tools;
}

public function __invoke(): Command
public function __invoke(Filter $filter): Command
{
return new MultiStepCommand(
$this->tools->all()->map(function (Tool $tool) {
$this->tools->all($filter)->map(function (Tool $tool) {
return $tool->testCommand();
})
);
Expand Down
20 changes: 18 additions & 2 deletions tests/Cli/Command/InstallCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Zalas\Toolbox\Cli\Command\InstallCommand;
use Zalas\Toolbox\Runner\Runner;
use Zalas\Toolbox\Tool\Command;
use Zalas\Toolbox\Tool\Filter;
use Zalas\Toolbox\UseCase\InstallTools;

class InstallCommandTest extends ToolboxCommandTestCase
Expand Down Expand Up @@ -34,7 +35,7 @@ protected function setUp()
public function test_it_runs_the_install_tools_use_case()
{
$command = $this->createCommand();
$this->useCase->__invoke()->willReturn($command);
$this->useCase->__invoke(Argument::type(Filter::class))->willReturn($command);
$this->runner->run($command)->willReturn(0);

$tester = $this->executeCliCommand();
Expand All @@ -46,14 +47,24 @@ public function test_it_runs_the_install_tools_use_case()

public function test_it_returns_the_status_code_of_the_run()
{
$this->useCase->__invoke()->willReturn($this->createCommand());
$this->useCase->__invoke(Argument::type(Filter::class))->willReturn($this->createCommand());
$this->runner->run(Argument::any())->willReturn(1);

$tester = $this->executeCliCommand();

$this->assertSame(1, $tester->getStatusCode());
}

public function test_it_excludes_tags()
{
$this->useCase->__invoke(Argument::type(Filter::class))->willReturn($this->createCommand());
$this->runner->run(Argument::any())->willReturn(0);

$this->executeCliCommand(['--exclude-tag' => ['foo']]);

$this->useCase->__invoke(new Filter(['foo']))->shouldBeCalled();
}

public function test_it_defines_dry_run_option()
{
$this->assertTrue($this->cliCommand()->getDefinition()->hasOption('dry-run'));
Expand All @@ -73,6 +84,11 @@ public function test_it_takes_the_target_dir_option_default_from_environment_if_
$this->assertSame('/tmp', $this->cliCommand()->getDefinition()->getOption('target-dir')->getDefault());
}

public function test_it_defines_exclude_tags_option()
{
$this->assertTrue($this->cliCommand()->getDefinition()->hasOption('exclude-tag'));
}

protected function getContainerTestDoubles(): array
{
return [
Expand Down
20 changes: 19 additions & 1 deletion tests/Cli/Command/ListCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

namespace Zalas\Toolbox\Tests\Cli\Command;

use Prophecy\Argument;
use Prophecy\Prophecy\ObjectProphecy;
use Zalas\Toolbox\Cli\Command\ListCommand;
use Zalas\Toolbox\Tool\Collection;
use Zalas\Toolbox\Tool\Filter;
use Zalas\Toolbox\Tool\Tool;
use Zalas\Toolbox\UseCase\ListTools;

Expand All @@ -26,7 +28,7 @@ protected function setUp()

public function test_it_runs_the_list_tools_use_case()
{
$this->useCase->__invoke()->willReturn(Collection::create([
$this->useCase->__invoke(Argument::type(Filter::class))->willReturn(Collection::create([
$this->createTool('Behat', 'Tests business expectations', 'http://behat.org'),
]));

Expand All @@ -37,6 +39,22 @@ public function test_it_runs_the_list_tools_use_case()
$this->assertRegExp('#Behat.*?Tests business expectations.*?http://behat.org#smi', $tester->getDisplay());
}

public function test_it_excludes_tags()
{
$this->useCase->__invoke(Argument::type(Filter::class))->willReturn(Collection::create([
$this->createTool('Behat', 'Tests business expectations', 'http://behat.org'),
]));

$this->executeCliCommand(['--exclude-tag' => ['foo']]);

$this->useCase->__invoke(new Filter(['foo']))->shouldHaveBeenCalled();
}

public function test_it_defines_exclude_tags_option()
{
$this->assertTrue($this->cliCommand()->getDefinition()->hasOption('exclude-tag'));
}

protected function getContainerTestDoubles(): array
{
return [
Expand Down
Loading

0 comments on commit 221c2f6

Please sign in to comment.