diff --git a/src/Task/BuiltIn/ExecTask.php b/src/Task/BuiltIn/ExecTask.php new file mode 100644 index 0000000..095add9 --- /dev/null +++ b/src/Task/BuiltIn/ExecTask.php @@ -0,0 +1,84 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Mage\Task\BuiltIn; + +use Mage\Task\Exception\ErrorException; +use Mage\Task\AbstractTask; + +/** + * Exec task. Allows you to execute arbitrary commands. + * + * @author Yanick Witschi + */ +class ExecTask extends AbstractTask +{ + /** + * @return string + */ + public function getName() + { + return 'exec'; + } + + /** + * @return string + */ + public function getDescription() + { + $options = $this->getOptions(); + + if ('' !== $options['descr']) { + return (string) $options['descr']; + } + + return '[Exec] Executing custom command'; + } + + /** + * @return bool + * + * @throws ErrorException + */ + public function execute() + { + $options = $this->getOptions(); + + if ('' === $options['cmd']) { + throw new ErrorException('What about if you gave me a command to execute?'); + } + + // If not jailed, it must run as remote command + if (false === $options['jail']) { + $process = $this->runtime->runRemoteCommand($options['cmd'], false, $options['timeout']); + return $process->isSuccessful(); + } + + $process = $this->runtime->runCommand($options['cmd'], $options['timeout']); + return $process->isSuccessful(); + } + + /** + * @return array + */ + protected function getOptions() + { + $options = array_merge([ + 'cmd' => '', + 'descr' => '', + 'jail' => true, + 'timeout' => 120 + ], + $this->options + ); + + return $options; + } +} diff --git a/tests/Command/BuiltIn/ExecTaskTest.php b/tests/Command/BuiltIn/ExecTaskTest.php new file mode 100644 index 0000000..ea1bae8 --- /dev/null +++ b/tests/Command/BuiltIn/ExecTaskTest.php @@ -0,0 +1,90 @@ +assertSame('exec', $task->getName()); + $this->assertSame('[Exec] Executing custom command', $task->getDescription()); + } + + public function testCustomDescription() + { + $task = new ExecTask(); + $task->setOptions(['descr' => '[My project] This is my wonderful task']); + $this->assertSame('[My project] This is my wonderful task', $task->getDescription()); + } + + /** + * @expectedException \Mage\Task\Exception\ErrorException + */ + public function testNoCommandProvided() + { + $task = new ExecTask(); + $task->execute(); + } + + public function testNonJailedCommand() + { + $runtime = $this->getMockBuilder(Runtime::class) + ->setMethods(['runRemoteCommand']) + ->getMock(); + + $runtime + ->expects($this->once()) + ->method('runRemoteCommand') + ->with('rm -rf /') + ->willReturn($this->mockProcess(true)); + + + $task = $this->getTask($runtime); + $task->setOptions(['cmd' => 'rm -rf /', 'jail' => false]); + $this->assertTrue($task->execute()); + } + + public function testRegularCommand() + { + $runtime = $this->getMockBuilder(Runtime::class) + ->setMethods(['runCommand']) + ->getMock(); + + $runtime + ->expects($this->once()) + ->method('runCommand') + ->with('rm -rf /', 10) + ->willReturn($this->mockProcess(true)); + + $task = $this->getTask($runtime); + $task->setOptions(['cmd' => 'rm -rf /', 'timeout' => 10]); + $task->execute(); + } + + private function getTask($runtime) + { + $task = new ExecTask(); + $task->setRuntime($runtime); + + return $task; + } + + private function mockProcess($successful) + { + $process = $this->getMockBuilder(Process::class) + ->disableOriginalConstructor() + ->getMock(); + $process + ->expects($this->any()) + ->method('isSuccessful') + ->willReturn($successful); + + return $process; + } +}