Talesoft/tale-dev-tool

View on GitHub
src/DevTool/Application.php

Summary

Maintainability
A
45 mins
Test Coverage
<?php
declare(strict_types=1);

namespace Tale\DevTool;

use Symfony\Component\Console\Exception\LogicException;
use Tale\DevTool\Command\CheckCommand;
use Tale\DevTool\Command\CodeStyleCheckCommand;
use Tale\DevTool\Command\CodeStyleFixCommand;
use Tale\DevTool\Command\CoverageCheckCommand;
use Tale\DevTool\Command\CoverageReportCommand;
use Tale\DevTool\Command\InstallCommand;
use Tale\DevTool\Command\UnitTestsRunCommand;
use RuntimeException;
use Symfony\Component\Console\Application as ConsoleApplication;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class Application extends ConsoleApplication
{
    public function __construct()
    {
        parent::__construct('Tale Dev Tool', '0.2.5');
        $this->configure();
    }

    /**
     *
     * @throws LogicException
     */
    protected function configure(): void
    {
        $this->add(new CheckCommand());
        $this->add(new CodeStyleCheckCommand());
        $this->add(new CodeStyleFixCommand());
        $this->add(new CoverageCheckCommand());
        $this->add(new CoverageReportCommand());
        $this->add(new InstallCommand());
        $this->add(new UnitTestsRunCommand());
    }

    public function getWorkingDirectory(): string
    {
        return getcwd();
    }

    protected function getConfigDirectory(): string
    {
        return \dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'config';
    }

    public function getConfigFilePath(string $fileName): string
    {
        $localPath = realpath($this->getWorkingDirectory().DIRECTORY_SEPARATOR.$fileName);

        if ($localPath) {
            return $localPath;
        }

        return $this->getConfigDirectory().DIRECTORY_SEPARATOR.$fileName;
    }

    public function isWindows(): bool
    {
        return strncmp(strtolower(PHP_OS), 'win', 3) === 0;
    }

    public function isUnix(): bool
    {
        return !$this->isWindows();
    }

    /**
     * @param string $command
     * @param OutputInterface $output
     * @param array|null $arguments
     * @return int
     * @throws \Symfony\Component\Console\Exception\CommandNotFoundException
     */
    public function runCommand(string $command, OutputInterface $output, array $arguments = null): int
    {
        $arguments = $arguments ?: [];
        $instance = $this->find($command);
        $arguments['command'] = $instance->getName();
        try {
            return $instance->run(new ArrayInput($arguments), $output);
        } catch (\Exception $e) {
            return 1;
        }
    }

    /**
     * @param $command
     * @return bool|string
     * @throws \RuntimeException
     */
    protected function getShellCommandPath(string $command): string
    {
        $cwd = $this->getWorkingDirectory();
        $commandPath = $cwd."/$command";

        //Check if there is a windows batch file equivalent for composer commands
        if ($this->isWindows() && ($batPath = realpath("$commandPath.bat"))) {
            $commandPath = $batPath;
        }

        if (!($commandPath = realpath($commandPath))) {
            throw new RuntimeException(
                "The given command [$command] was not found"
            );
        }

        return $commandPath;
    }

    public function runShellCommand(string $command, array $arguments = null): int
    {
        $arguments = $arguments ?: [];
        $parts = [escapeshellcmd($command)];

        foreach ($arguments as $key => $arg) {
            if (\is_bool($arg)) {
                if (!$arg) {
                    continue;
                }
                $arg = $key;
            } elseif (!\is_int($key)) {
                $arg = "$key=$arg";
            }

            $parts[] = escapeshellarg($arg);
        }

        passthru(implode(' ', $parts), $returnCode);
        return (int)$returnCode;
    }

    /**
     * @param $name
     * @param array|null $arguments
     * @return int
     * @throws \RuntimeException
     */
    public function runVendorCommand(string $name, array $arguments = null): int
    {
        return $this->runShellCommand($this->getShellCommandPath("vendor/bin/$name"), $arguments);
    }

    /**
     * @param array|null $arguments
     * @return int
     * @throws \RuntimeException
     */
    public function runUnitTests(array $arguments = null): int
    {
        return $this->runVendorCommand('phpunit', $arguments);
    }

    /**
     * @param array|null $arguments
     * @return int
     * @throws \RuntimeException
     */
    public function runCodeStyleChecker(array $arguments = null): int
    {
        $arguments = $arguments ?: [];

        $arguments[] = '--colors';

        return $this->runVendorCommand('phpcs', $arguments);
    }

    /**
     * @param array|null $arguments
     * @return int
     * @throws \RuntimeException
     */
    public function runCodeStyleFixer(array $arguments = null): int
    {
        return $this->runVendorCommand('phpcbf', $arguments);
    }

    /**
     * @param array|null $arguments
     * @return int
     * @throws \RuntimeException
     */
    public function runCoverageReporter(array $arguments = null): int
    {
        return $this->runVendorCommand('test-reporter', $arguments);
    }

    /**
     * @param InputInterface|null $input
     * @param OutputInterface|null $output
     * @return int
     * @throws \Exception
     */
    public function run(InputInterface $input = null, OutputInterface $output = null): int
    {
        $this->configure();

        return parent::run($input, $output);
    }
}