Skip to content

Commit

Permalink
Merge pull request #11 from ash-jc-allen/v2.0.0
Browse files Browse the repository at this point in the history
v2.0.0
  • Loading branch information
ash-jc-allen authored Sep 16, 2020
2 parents e3aacf8 + 02bed0d commit 817dbfd
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 32 deletions.
33 changes: 12 additions & 21 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,40 +4,31 @@ matrix:
fast_finish: true
include:
# Laravel 6.*
# --> PHP 7.2
- php: 7.2
env: LARAVEL='6.*' TESTBENCH='4.*' COMPOSER_FLAGS='--prefer-lowest'
- php: 7.2
env: LARAVEL='6.*' TESTBENCH='4.*' COMPOSER_FLAGS='--prefer-stable'
# --> PHP 7.3
- php: 7.3
env: LARAVEL='6.*' TESTBENCH='4.*' COMPOSER_FLAGS='--prefer-lowest'
env: LARAVEL='6.*'
- php: 7.3
env: LARAVEL='6.*' TESTBENCH='4.*' COMPOSER_FLAGS='--prefer-stable'
# --> PHP 7.4
env: LARAVEL='6.*'
- php: 7.4
env: LARAVEL='6.*' TESTBENCH='4.*' COMPOSER_FLAGS='--prefer-stable'
env: LARAVEL='6.*'
# Laravel 7.*
# --> PHP 7.2
- php: 7.2
env: LARAVEL='7.*' TESTBENCH='4.*' COMPOSER_FLAGS='--prefer-lowest'
- php: 7.2
env: LARAVEL='7.*' TESTBENCH='4.*' COMPOSER_FLAGS='--prefer-stable'
# --> PHP 7.3
env: LARAVEL='7.*'
- php: 7.3
env: LARAVEL='7.*' TESTBENCH='4.*' COMPOSER_FLAGS='--prefer-lowest'
env: LARAVEL='7.*'
- php: 7.4
env: LARAVEL='7.*'
# Laravel 8.*
- php: 7.3
env: LARAVEL='7.*' TESTBENCH='4.*' COMPOSER_FLAGS='--prefer-stable'
# --> PHP 7.4
env: LARAVEL='8.*'
- php: 7.4
env: LARAVEL='7.*' TESTBENCH='4.*' COMPOSER_FLAGS='--prefer-stable'
env: LARAVEL='8.*'

before_install:
- travis_retry composer self-update
- travis_retry composer require --no-update --no-interaction "orchestra/testbench:${TESTBENCH}"
- travis_retry composer require --no-update --no-interaction "illuminate/container:${LARAVEL}"

install:
- travis_retry composer update ${COMPOSER_FLAGS} --prefer-dist --no-interaction --no-suggest
- travis_retry composer update --prefer-dist --no-interaction --no-suggest
- travis_retry composer du -o

script:
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

**v2.0.0 (released 2020-09-16):**
- Added the functionality to run interactive commands. [#9](https://github.com/ash-jc-allen/laravel-executor/pull/9) [#10](https://github.com/ash-jc-allen/laravel-executor/pull/10)
- Added support for Laravel 8 and Guzzle 7. [#12](https://github.com/ash-jc-allen/laravel-executor/pull/12)

**v1.1.0 (released 2020-07-07):**
- Added a new ``` ->ping() ``` method to the Executors that can be used to ping a URL.

Expand Down
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ class AppUpdate extends Executor
}
```

Note: In some cases, you may want to run a command that requires your input. For example, you might have a command that
creates a new user in the database and need you to input some details. In this case, you can pass ``` true ``` as the second
parameter to the ``` ->runArtisan() ``` command to specify that it is an interactive command.

#### Adding a Command
To run a command (that can't be run with Artisan) via your Executor class, you can add the ``` runExternal() ``` method to your Executor's ``` run() ```
method. For example, the code below shows how you could set the Executor to run the built-in Composer ``` composer install ```
Expand All @@ -124,6 +128,10 @@ class AppUpdate extends Executor
}
```

Note: In some cases, you may want to run a command that requires your input. For example, you might have a command that
creates a new user in the database and need you to input some details. In this case, you can pass ``` true ``` as the second
parameter to the ``` ->runArtisan() ``` command to specify that it is an interactive command.

#### Adding a Closure
Sometimes you might want to run some code that doesn't necessarily fit into an existing command. In this case, you can add a closure
to your Executor instead. The example below shows how to pass a simple closure to your Executor class:
Expand Down Expand Up @@ -309,6 +317,7 @@ Note: A contribution guide will be added soon.
## Credits

- [Ash Allen](https://ashallendesign.co.uk)
- [Ahmad Masabni](https://github.com/masabni)
- [Jess Pickup](https://jesspickup.co.uk) (Logo)
- [All Contributors](https://github.com/ash-jc-allen/laravel-executor/graphs/contributors)

Expand Down
10 changes: 5 additions & 5 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@
"require": {
"php": "^7.2",
"nesbot/carbon": "~2.0",
"guzzlehttp/guzzle": "^6.3",
"illuminate/container": "^6.0|^7.0",
"ext-json": "*",
"jolicode/jolinotif": "^2.1"
"guzzlehttp/guzzle": "^6.3|^7.0",
"illuminate/container": "^6.0|^7.0|^8.0",
"jolicode/jolinotif": "^2.1",
"ext-json": "*"
},
"require-dev": {
"mockery/mockery": "^1.0",
"orchestra/testbench": "^3.8 || ^4.0",
"orchestra/testbench": "^3.8|^4.0|^5.0|^6.0",
"phpunit/phpunit": "^8.2"
},
"autoload": {
Expand Down
66 changes: 60 additions & 6 deletions src/Classes/Executor.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

namespace AshAllenDesign\LaravelExecutor\Classes;

use AshAllenDesign\LaravelExecutor\Exceptions\ExecutorException;
use AshAllenDesign\LaravelExecutor\Traits\DesktopNotifications;
use Closure;
use GuzzleHttp\Client;
use Illuminate\Support\Facades\App;
use Joli\JoliNotif\Notifier;
use Joli\JoliNotif\NotifierFactory;
use Symfony\Component\Process\Process;
Expand Down Expand Up @@ -60,13 +62,17 @@ abstract public function run(): self;
* should be executed.
*
* @param string $command
* @param bool $isInteractive
* @return $this
* @throws ExecutorException
*/
public function runArtisan(string $command): self
public function runArtisan(string $command, bool $isInteractive = false): self
{
$this->validateCommand($command, $isInteractive);

$command = 'php artisan '.$command;

$this->runCommand($command);
$this->runCommand($command, $isInteractive);

return $this;
}
Expand All @@ -76,11 +82,15 @@ public function runArtisan(string $command): self
* items that should be executed.
*
* @param string $command
* @param bool $isInteractive
* @return $this
* @throws ExecutorException
*/
public function runExternal(string $command): self
public function runExternal(string $command, bool $isInteractive = false): self
{
$this->runCommand($command);
$this->validateCommand($command, $isInteractive);

$this->runCommand($command, $isInteractive);

return $this;
}
Expand Down Expand Up @@ -124,10 +134,17 @@ public function ping(string $url, array $headers = []): self
/**
* Handle the running of a console command.
*
* @param string $commandToRun
* @param string $commandToRun
* @param bool $isInteractive
*/
private function runCommand(string $commandToRun): void
private function runCommand(string $commandToRun, bool $isInteractive = false): void
{
if ($isInteractive) {
$this->runInteractiveCommand($commandToRun);

return;
}

$process = new Process(explode(' ', $commandToRun));

$process->setWorkingDirectory(base_path());
Expand All @@ -143,6 +160,43 @@ private function runCommand(string $commandToRun): void
$this->setOutput($this->getOutput().$output);
}

/**
* Handle the running of an interactive console command.
*
* @param string $commandToRun
*/
private function runInteractiveCommand(string $commandToRun): void
{
passthru(escapeshellcmd($commandToRun), $status);

if ($status == 0) {
$this->setOutput($this->getOutput().' Interactive command completed');
} else {
$this->setOutput($this->getOutput().' Interactive command failed');
}
}

/**
* Validate whether if the command can be run. We check
* that an interactive command can only be run inside
* the console. This is because there would be no
* way for a user to interact with the command
* if it is was running through a controller.
*
* @param string $command
* @param bool $isInteractive
* @return bool
* @throws ExecutorException
*/
private function validateCommand(string $command, bool $isInteractive): bool
{
if (! App::runningInConsole() && $isInteractive) {
throw new ExecutorException('Interactive commands can only be run in the console.');
}

return true;
}

/**
* Get the output from the commands that have been ran.
* We can use this for displaying to the console.
Expand Down
9 changes: 9 additions & 0 deletions src/Exceptions/ExecutorException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace AshAllenDesign\LaravelExecutor\Exceptions;

use Exception;

class ExecutorException extends Exception
{
}
52 changes: 52 additions & 0 deletions tests/Unit/Classes/ExecutorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
namespace AshAllenDesign\LaravelExecutor\Tests\Unit\Classes;

use AshAllenDesign\LaravelExecutor\Classes\Executor;
use AshAllenDesign\LaravelExecutor\Exceptions\ExecutorException;
use AshAllenDesign\LaravelExecutor\Tests\Unit\TestCase;
use GuzzleHttp\Client;
use Hamcrest\Matchers;
use Illuminate\Support\Facades\App;
use Joli\JoliNotif\Notification;
use Joli\JoliNotif\NotifierFactory;
use Mockery;
Expand Down Expand Up @@ -103,6 +105,56 @@ public function run(): Executor
$this->assertEquals('ashallendesign', trim($executor->getOutput()));
}

/** @test */
public function interactive_command_added_to_the_executor_can_be_run()
{
$executor = new class extends Executor {
public function run(): Executor
{
return $this->runExternal('echo anything', true);
}
};

$executor->run();
$this->assertEquals('Interactive command completed', trim($executor->getOutput()));
}

/** @test */
public function interactive_external_command_cannot_be_run_outside_of_console_mode()
{
$this->expectException(ExecutorException::class);
$this->expectExceptionMessage('Interactive commands can only be run in the console.');

App::shouldReceive('runningInConsole')->andReturnFalse();

$executor = new class extends Executor {
public function run(): Executor
{
return $this->runExternal('echo anything', true);
}
};

$executor->run();
}

/** @test */
public function interactive_artisan_command_cannot_be_run_outside_of_console_mode()
{
$this->expectException(ExecutorException::class);
$this->expectExceptionMessage('Interactive commands can only be run in the console.');

App::shouldReceive('runningInConsole')->andReturnFalse();

$executor = new class extends Executor {
public function run(): Executor
{
return $this->runArtisan('', true);
}
};

$executor->run();
}

/** @test */
public function url_can_be_pinged()
{
Expand Down

0 comments on commit 817dbfd

Please sign in to comment.