-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(documentator):
include:artisan
instruction (#166)
- Loading branch information
Showing
23 changed files
with
397 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
26 changes: 26 additions & 0 deletions
26
...umentator/src/Preprocessor/Instructions/IncludeArtisan/Exceptions/ArtisanCommandError.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
<?php declare(strict_types = 1); | ||
|
||
namespace LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions\IncludeArtisan\Exceptions; | ||
|
||
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Context; | ||
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Exceptions\InstructionFailed; | ||
use Throwable; | ||
|
||
use function sprintf; | ||
|
||
class ArtisanCommandError extends InstructionFailed { | ||
public function __construct( | ||
Context $context, | ||
Throwable $previous = null, | ||
) { | ||
parent::__construct( | ||
$context, | ||
sprintf( | ||
'Artisan command `%s` failed (in `%s`).', | ||
$context->target, | ||
$context->file->getRelativePath($context->root), | ||
), | ||
$previous, | ||
); | ||
} | ||
} |
32 changes: 32 additions & 0 deletions
32
...mentator/src/Preprocessor/Instructions/IncludeArtisan/Exceptions/ArtisanCommandFailed.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
<?php declare(strict_types = 1); | ||
|
||
namespace LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions\IncludeArtisan\Exceptions; | ||
|
||
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Context; | ||
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Exceptions\InstructionFailed; | ||
use Throwable; | ||
|
||
use function sprintf; | ||
|
||
class ArtisanCommandFailed extends InstructionFailed { | ||
public function __construct( | ||
Context $context, | ||
private readonly int $result, | ||
Throwable $previous = null, | ||
) { | ||
parent::__construct( | ||
$context, | ||
sprintf( | ||
'Artisan command `%s` exited with status code `%s` (in `%s`).', | ||
$context->target, | ||
$this->result, | ||
$context->file->getRelativePath($context->root), | ||
), | ||
$previous, | ||
); | ||
} | ||
|
||
public function getResult(): int { | ||
return $this->result; | ||
} | ||
} |
73 changes: 73 additions & 0 deletions
73
packages/documentator/src/Preprocessor/Instructions/IncludeArtisan/Instruction.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
<?php declare(strict_types = 1); | ||
|
||
namespace LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions\IncludeArtisan; | ||
|
||
use Exception; | ||
use Illuminate\Contracts\Console\Kernel; | ||
use LastDragon_ru\LaraASP\Core\Application\ApplicationResolver; | ||
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Context; | ||
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Contracts\Instruction as InstructionContract; | ||
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Exceptions\InstructionFailed; | ||
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions\IncludeArtisan\Exceptions\ArtisanCommandError; | ||
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions\IncludeArtisan\Exceptions\ArtisanCommandFailed; | ||
use Override; | ||
use Symfony\Component\Console\Command\Command; | ||
use Symfony\Component\Console\Input\StringInput; | ||
use Symfony\Component\Console\Output\BufferedOutput; | ||
|
||
use function trim; | ||
|
||
/** | ||
* Executes the `<target>` as Artisan command and returns result. | ||
* | ||
* Please note that the working directory will not be changed to the file | ||
* directory (like `include:exec` do). This behavior is close to how Artisan | ||
* normally works (I'm also not sure that it is possible to change the current | ||
* working directory in any robust way when you call Artisan command from code). | ||
* You can use one of the special variables inside command args instead. | ||
* | ||
* @implements InstructionContract<string, null> | ||
*/ | ||
class Instruction implements InstructionContract { | ||
public function __construct( | ||
protected readonly ApplicationResolver $application, | ||
) { | ||
// empty | ||
} | ||
|
||
#[Override] | ||
public static function getName(): string { | ||
return 'include:artisan'; | ||
} | ||
|
||
#[Override] | ||
public static function getResolver(): string { | ||
return Resolver::class; | ||
} | ||
|
||
#[Override] | ||
public static function getParameters(): ?string { | ||
return null; | ||
} | ||
|
||
#[Override] | ||
public function __invoke(Context $context, mixed $target, mixed $parameters): string { | ||
try { | ||
$app = $this->application->getInstance(); | ||
$kernel = $app->make(Kernel::class); | ||
$input = new StringInput($target); | ||
$output = new BufferedOutput(); | ||
$result = $kernel->handle($input, $output); | ||
|
||
if ($result !== Command::SUCCESS) { | ||
throw new ArtisanCommandFailed($context, $result); | ||
} | ||
|
||
return trim($output->fetch()); | ||
} catch (InstructionFailed $exception) { | ||
throw $exception; | ||
} catch (Exception $exception) { | ||
throw new ArtisanCommandError($context, $exception); | ||
} | ||
} | ||
} |
132 changes: 132 additions & 0 deletions
132
packages/documentator/src/Preprocessor/Instructions/IncludeArtisan/InstructionTest.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
<?php declare(strict_types = 1); | ||
|
||
namespace LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions\IncludeArtisan; | ||
|
||
use Composer\InstalledVersions; | ||
use Composer\Semver\VersionParser; | ||
use Illuminate\Contracts\Console\Kernel; | ||
use LastDragon_ru\LaraASP\Core\Utils\Path; | ||
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Context; | ||
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions\IncludeArtisan\Exceptions\ArtisanCommandFailed; | ||
use LastDragon_ru\LaraASP\Documentator\Processor\FileSystem\Directory; | ||
use LastDragon_ru\LaraASP\Documentator\Processor\FileSystem\File; | ||
use LastDragon_ru\LaraASP\Documentator\Testing\Package\ProcessorHelper; | ||
use LastDragon_ru\LaraASP\Documentator\Testing\Package\TestCase; | ||
use Mockery\MockInterface; | ||
use PHPUnit\Framework\Attributes\CoversClass; | ||
use Symfony\Component\Console\Command\Command; | ||
use Symfony\Component\Console\Input\InputInterface; | ||
use Symfony\Component\Console\Output\OutputInterface; | ||
|
||
use function sprintf; | ||
|
||
/** | ||
* @internal | ||
*/ | ||
#[CoversClass(Instruction::class)] | ||
final class InstructionTest extends TestCase { | ||
public function testInvoke(): void { | ||
$root = new Directory(Path::normalize(__DIR__), false); | ||
$file = new File(Path::normalize(__FILE__), false); | ||
$params = null; | ||
$expected = 'result'; | ||
$command = 'command to execute'; | ||
$context = new Context($root, $file, $command, $params); | ||
$instance = $this->app()->make(Instruction::class); | ||
|
||
$this->override(Kernel::class, static function (MockInterface $mock) use ($command, $expected): void { | ||
if (InstalledVersions::satisfies(new VersionParser(), 'illuminate/contracts', '^11.0.0')) { | ||
// todo(documentator): Remove after https://github.com/LastDragon-ru/lara-asp/issues/143 | ||
$mock | ||
->shouldReceive('addCommands') | ||
->atLeast() | ||
->once() | ||
->andReturns(); | ||
$mock | ||
->shouldReceive('addCommandPaths') | ||
->atLeast() | ||
->once() | ||
->andReturns(); | ||
$mock | ||
->shouldReceive('addCommandRoutePaths') | ||
->atLeast() | ||
->once() | ||
->andReturns(); | ||
} | ||
|
||
$mock | ||
->shouldReceive('handle') | ||
->withArgs( | ||
static function (InputInterface $input) use ($command): bool { | ||
return (string) $input === $command; | ||
}, | ||
) | ||
->once() | ||
->andReturnUsing( | ||
static function (InputInterface $input, OutputInterface $output) use ($expected): int { | ||
$output->writeln($expected); | ||
|
||
return Command::SUCCESS; | ||
}, | ||
); | ||
}); | ||
|
||
self::assertEquals($expected, ProcessorHelper::runInstruction($instance, $context, $command, $params)); | ||
} | ||
|
||
public function testInvokeFailed(): void { | ||
$root = new Directory(Path::normalize(__DIR__), false); | ||
$file = new File(Path::normalize(__FILE__), false); | ||
$params = null; | ||
$command = 'command to execute'; | ||
$context = new Context($root, $file, $command, $params); | ||
$instance = $this->app()->make(Instruction::class); | ||
|
||
$this->override(Kernel::class, static function (MockInterface $mock) use ($command): void { | ||
// todo(documentator): Remove after https://github.com/LastDragon-ru/lara-asp/issues/143 | ||
if (InstalledVersions::satisfies(new VersionParser(), 'illuminate/contracts', '^11.0.0')) { | ||
$mock | ||
->shouldReceive('addCommands') | ||
->atLeast() | ||
->once() | ||
->andReturns(); | ||
$mock | ||
->shouldReceive('addCommandPaths') | ||
->atLeast() | ||
->once() | ||
->andReturns(); | ||
$mock | ||
->shouldReceive('addCommandRoutePaths') | ||
->atLeast() | ||
->once() | ||
->andReturns(); | ||
} | ||
|
||
$mock | ||
->shouldReceive('handle') | ||
->withArgs( | ||
static function (InputInterface $input) use ($command): bool { | ||
return (string) $input === $command; | ||
}, | ||
) | ||
->once() | ||
->andReturnUsing( | ||
static function (): int { | ||
return Command::FAILURE; | ||
}, | ||
); | ||
}); | ||
|
||
self::expectException(ArtisanCommandFailed::class); | ||
self::expectExceptionMessage( | ||
sprintf( | ||
'Artisan command `%s` exited with status code `%s` (in `%s`).', | ||
$command, | ||
Command::FAILURE, | ||
$context->file->getRelativePath($context->root), | ||
), | ||
); | ||
|
||
ProcessorHelper::runInstruction($instance, $context, $command, $params); | ||
} | ||
} |
Oops, something went wrong.