5分で自動コード検証

このチュートリアルでは、phpプロジェクトでコードスタイルのチェックを自動化する方法を示します。



新しいプロジェクトでセットアップがどのように表示されるかを見てみましょう。



ステップ1-コンポーザーを初期化します(既に構成されている場合はスキップします)



これを行うには、プロジェクトのルートでコマンドを実行します。Composerがインストールされていない場合は、getcomposer.orgの公式ドキュメントを参照してください。



composer init

      
      





ステップ2-.gitignoreを追加します



###> phpstorm ###
.idea
###< phpstorm ###

/vendor/

###> friendsofphp/php-cs-fixer ###
/.php_cs
/.php_cs.cache
###< friendsofphp/php-cs-fixer ###

      
      





ステップ3-必要なライブラリを追加する



composer require --dev friendsofphp/php-cs-fixer symfony/process symfony/console  squizlabs/php_codesniffer

      
      





ステップ4-フックハンドラーを追加する



ハンドラー自体は何にでも書くことができますが、記事はphpに関するものなので、コードを記述します。



hooks /pre-commit.phpフォルダーにファイルを作成します
#!/usr/bin/php

<?php
define('VENDOR_DIR', __DIR__.'/../../vendor');
require VENDOR_DIR.'/autoload.php';

use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Application;
use Symfony\Component\Process\Process;

class CodeQualityTool extends Application
{
    /**
     * @var OutputInterface
     */
    private $output;
    /**
     * @var InputInterface
     */
    private $input;

    const PHP_FILES_IN_SRC = '/^src\/(.*)(\.php)$/';

    public function __construct()
    {
        parent::__construct('Ecombo Quality Tool', '1.0.0');
    }

    /**
     * @param InputInterface $input
     * @param OutputInterface $output
     *
     * @return void
     * @throws \Exception
     */
    public function doRun(InputInterface $input, OutputInterface $output)
    {
        $this->input = $input;
        $this->output = $output;
        $output->writeln('<fg=white;options=bold;bg=red>Code Quality Tool</fg=white;options=bold;bg=red>');
        $output->writeln('<info>Fetching files</info>');
        $files = $this->extractCommitedFiles();
        $output->writeln('<info>Running PHPLint</info>');

        if (! $this->phpLint($files)) {
            throw new \Exception('There are some PHP syntax errors!');
        }

        $output->writeln('<info>Checking code style with PHPCS</info>');

        if (! $this->codeStylePsr($files)) {
            throw new \Exception(sprintf('There are PHPCS coding standards violations!'));
        }

        $output->writeln('<info>Well done!</info>');
    }

    /**
     * @return array
     */
    private function extractCommitedFiles()
    {
        $output = array();
        $against = 'HEAD';
        exec("git diff-index --cached --name-status $against | egrep '^(A|M)' | awk '{print $2;}'", $output);

        return $output;
    }

    /**
     * @param array $files
     *
     * @return bool
     *
     * @throws \Exception
     */
    private function phpLint($files)
    {
        $needle = '/(\.php)|(\.inc)$/';
        $succeed = true;

        foreach ($files as $file) {
            if (! preg_match($needle, $file)) {
                continue;
            }

            $process = new Process(['php', '-l', $file]);
            $process->run();

            if (! $process->isSuccessful()) {
                $this->output->writeln($file);
                $this->output->writeln(sprintf('<error>%s</error>', trim($process->getErrorOutput())));

                if ($succeed) {
                    $succeed = false;
                }
            }
        }

        return $succeed;
    }

    /**
     * @param array $files
     *
     * @return bool
     */
    private function codeStylePsr(array $files)
    {
        $succeed = true;
        $needle = self::PHP_FILES_IN_SRC;
        $standard = 'PSR2';

        foreach ($files as $file) {
            if (! preg_match($needle, $file)) {
                continue;
            }

            $phpCsFixer = new Process([
                'php',
                VENDOR_DIR.'/bin/phpcs',
                '-n',
                '--standard='.$standard,
                $file,
            ]);

            $phpCsFixer->setWorkingDirectory(__DIR__.'/../../');
            $phpCsFixer->run();

            if (! $phpCsFixer->isSuccessful()) {
                $this->output->writeln(sprintf('<error>%s</error>', trim($phpCsFixer->getOutput())));

                if ($succeed) {
                    $succeed = false;
                }
            }
        }

        return $succeed;
    }
}

$console = new CodeQualityTool();
$console->run();

      
      









この例では、コードは3つのチェックに合格

します

。-構文エラーをチェックします -コードスニファを介してPSR2をチェックしますPSR2は、コードスニファ



をサポートする他のチェックに 置き換えることができます。サポートされている規格のリストは、コマンドを入力すると表示されます



 vendor/bin/phpcs -i

      
      







ステップ5-自動開始のコミット前チェックを実装するようにcomposerを構成する



検証コードをprecommitフックで実行するには、手順3で作成したコードを含むファイルを.git / hooks / pre-commitフォルダーに配置する必要があります。これは手動で行うことができますが、この問題を自動化する方がはるかに便利です。これを行うには、このファイルをコピーして、composerのインストール後に呼び出されるイベントでハングさせるハンドラーを作成する必要があります。これを行うには、次のようにします。

5.1pre-commit.phpファイルをgithooksフォルダーにコピーするハンドラー自体を作成します



ファイルsrc / Composer /ScriptHandler.phpを作成します
<?php

namespace App\Composer;

use Composer\Script\Event;

class ScriptHandler
{
    /**
     * @param Event $event
     *
     * @return bool
     */
    public static function preHooks(Event $event)
    {
        $io = $event->getIO();
        $gitHook = '.git/hooks/pre-commit';

        if (file_exists($gitHook)) {
            unlink($gitHook);
            $io->write('<info>Pre-commit hook removed!</info>');
        }

        return true;
    }

    /**
     * @param Event $event
     *
     * @return bool
     *
     * @throws \Exception
     */
    public static function postHooks(Event $event)
    {
        /** @var array $extras */
        $extras = $event->getComposer()->getPackage()->getExtra();

        if (! array_key_exists('hooks', $extras)) {
            throw new \InvalidArgumentException('The parameter handler needs to be configured through the extra.hooks setting.');
        }
        $configs = $extras['hooks'];
        if (! array_key_exists('pre-commit', $configs)) {
            throw new \InvalidArgumentException('The parameter handler needs to be configured through the extra.hooks.pre-commit setting.');
        }

        if (file_exists('.git/hooks')) {
            /** @var \Composer\IO\IOInterface $io */
            $io = $event->getIO();
            $gitHook = '.git/hooks/pre-commit';
            $docHook = $configs['pre-commit'];
            copy($docHook, $gitHook);
            chmod($gitHook, 0777);
            $io->write('<info>Pre-commit hook created!</info>');
        }

        return true;
    }
}

      
      





5.2 composer

composer.json



    "scripts": {
        "post-install-cmd": [
            "App\\Composer\\ScriptHandler::postHooks"
        ],
        "post-update-cmd": [
            "App\\Composer\\ScriptHandler::postHooks"
        ],
        "pre-update-cmd": "App\\Composer\\ScriptHandler::preHooks",
        "pre-install-cmd": "App\\Composer\\ScriptHandler::preHooks"
    },
    "extra": {
        "hooks": {
            "pre-commit": "hooks/pre-commit.php"
        }
    }

      
      









pre-update-cmd, pre-install-cmd



-インストールと更新の前に、古いハンドラー



post-install-cmd, post-update-cmd



削除されます -インストールと更新の後に、ハンドラーはpre commitに設定されます。



その結果、filekikcomposer.jsonは次の形式になります。



composer.json
{
    "name": "admin/test",
    "authors": [
        {
            "name": "vitaly.gorbunov",
            "email": "cezar62882@gmail.com"
        }
    ],
    "minimum-stability": "stable",
    "require": {},
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    },
    "scripts": {
        "post-install-cmd": [
            "App\\Composer\\ScriptHandler::postHooks"
        ],
        "post-update-cmd": [
            "App\\Composer\\ScriptHandler::postHooks"
        ],
        "pre-update-cmd": "App\\Composer\\ScriptHandler::preHooks",
        "pre-install-cmd": "App\\Composer\\ScriptHandler::preHooks"
    },
    "require-dev": {
        "friendsofphp/php-cs-fixer": "^2.16",
        "symfony/process": "^5.0",
        "symfony/console": "^5.0",
        "squizlabs/php_codesniffer": "^3.5"
    },
    "extra": {
        "hooks": {
            "pre-commit": "hooks/pre-commit.php"
        }
    }
}

      
      









必要に応じてファイルがコピーされるように、composerinstallを再度実行します。



すべての準備が整いました。曲がったコードスタイルでコードをコミットしようとすると、gitコンソールがそのことを通知します。



例として、次の内容のファイルMyClass.phpをsrcフォルダーに作成してみましょう。



<?php

namespace App;

class MyClass
{

    private $var1; private $var2;

    public function __construct() {
    }

    public function test() {

    }
}

      
      





コミットしてコード検証エラーを取得しようとします。



MBP-Admin:test admin$ git commit -am 'test'

Code Quality Tool
Fetching files
Running PHPLint
Checking code style with PHPCS
FILE: /Users/admin/projects/test/src/MyClass.php
----------------------------------------------------------------------
FOUND 5 ERRORS AFFECTING 5 LINES
----------------------------------------------------------------------
  8 | ERROR | [x] Each PHP statement must be on a line by itself
 10 | ERROR | [x] Opening brace should be on a new line
 13 | ERROR | [x] Opening brace should be on a new line
 15 | ERROR | [x] Function closing brace must go on the next line
    |       |     following the body; found 1 blank lines before
    |       |     brace
 16 | ERROR | [x] Expected 1 newline at end of file; 0 found
----------------------------------------------------------------------
PHPCBF CAN FIX THE 5 MARKED SNIFF VIOLATIONS AUTOMATICALLY
----------------------------------------------------------------------

Time: 49ms; Memory: 6MB

In pre-commit line 53:
                                                
  There are PHPCS coding standards violations!                      

      
      





やあ、すべてがうまくいく。



All Articles