Статьи

Проверка качества кода PHP с помощью Scrutinizer

Эта статья была немного пересмотрена, основываясь на отзывах людей, стоящих за Scrutinizer. По большей части изменения внесены в раздел «Конфигурация», который теперь заметно проще.

Мы прошли немало учебников по качеству кода, проверкам, системам автоматической сборки и так далее здесь, на SitePoint:

В этой статье мы рассмотрим Scrutinizer CI — инструмент непрерывной интеграции, довольно дорогой и закрытый для частных проектов, но очень удобный для общедоступных.

Scrutinizer vs / + Трэвис

Scrutinizer выполняет много анализов, которые выполняет компилятор, чтобы помочь вам найти потенциальные ошибки, уязвимости безопасности или нарушения передовых методов. Он также позволяет объединять его результаты с результатами некоторых инструментов с открытым исходным кодом, таких как PHP Code Sniffer, которые мы обсуждали в нашей серии из 4 статей о Jenkins.

В тех случаях, когда Travis полностью настраиваемый, с различными виртуальными средами, выполняющими ваш код и сообщающими вам о состоянии вашей сборки, он на самом деле не имеет встроенной поддержки для обеспечения качества. Scrutinizer это делает, но он не запускает тесты для общедоступных проектов, а для запуска частных проектов вам нужен платный план.

Поэтому Scrutinizer не может запустить PHPUnit для вас и не может предоставить статус сборки или покрытие кода. Однако мы можем настроить Travis для отправки отчетов о покрытии в Scrutinizer при каждой сборке. Таким образом, всякий раз, когда Travis создает новую сборку вашего проекта, он также автоматически проверяет актуальность отчета Scrutinizer.

Внешнее покрытие кода

Чтобы начать работу с Scrutinizer, зарегистрируйтесь там. Затем подключите к нему свою учетную запись Github и авторизуйте доступ, чтобы он мог добраться до ваших репозиториев и подтвердить, что вы являетесь его владельцем. Наконец, нажмите кнопку Добавить репозиторий и добавьте тот, который вы хотите проверить. Scrutinizer автоматически добавит веб-крючок в ваш репозиторий, чтобы все происходящие на нем события автоматически запускали процесс сканирования:

Github Scrutinizer Webhook

Я предполагаю, что вы уже знаете, как настроить Трэвис. Если нет, пожалуйста, посмотрите этот пост и возвращайтесь. В конце нашего файла .travis.yml нам нужно добавить следующее:

 script: - phpunit --coverage-text --coverage-clover=coverage.clover after_script: - wget https://scrutinizer-ci.com/ocular.phar - php ocular.phar code-coverage:upload --format=php-clover coverage.clover 

Сначала он инструктирует Трэвиса, что нужно сделать для запуска процесса сборки: запустите PHPUnit и создайте отчет о покрытии клевером. После выполнения сборки Travis необходимо загрузить помощник ocular.phar из Scrutinizer и использовать этот инструмент для отправки отчета о покрытии. Это означает, что, если вы предпочитаете вообще обходить Travis, вы также можете использовать этот инструмент со своей машины — просто запускайте те же команды локально.

конфигурация

Когда вы добавляете свой проект, Scrutinizer автоматически выведет конфигурацию на основе структуры вашего проекта. Он распознает многие распространенные фреймворки и CMS, такие как Symfony, Zend, Laravel, Drupal, Magento или WordPress, и автоматически настроит свой анализ в соответствии с этим конкретным проектом. Scrutinizer также позволяет изменить его поведение через файл конфигурации. Процесс настройки слишком универсален для удобства, поэтому я постараюсь максимально упростить.

Глобал / Репо

Существуют конфигурации, которые вы сохраняете на веб-сайте Scrutinizer, в своей учетной записи — глобальные и репо . Глобальная конфигурация может быть общей для репозиториев (но не обязательно — слово global означает, что она доступна глобально , а не глобально активна ).

Конфигурация репо — это конфигурация, сохраненная в разделе конфигурации репо:

Configuration screen

Сначала он будет пустым с некоторыми значениями по умолчанию . Чтобы настроить его, можно просто ввести пользовательские значения в соответствии с документами . В случае флиги / скелета это уже прекрасно определено, так что вы можете оторвать их конфигурацию и вставить туда прямо:

 filter: excluded_paths: [tests/*] checks: php: code_rating: true remove_extra_empty_lines: true remove_php_closing_tag: true remove_trailing_whitespace: true fix_use_statements: remove_unused: true preserve_multiple: false preserve_blanklines: true order_alphabetically: true fix_php_opening_tag: true fix_linefeed: true fix_line_ending: true fix_identation_4spaces: true fix_doc_comments: true tools: external_code_coverage: timeout: 600 runs: 3 

Когда процесс сборки запускается (и это произойдет автоматически из-за веб-крюка), Travis запустит команду PHPUnit и отправит отчет о покрытии, когда это будет сделано. Тайм-аут 600 секунд означает, что это максимальное количество времени, которое Scrutinizer будет терпеть, ожидая получения отчета о покрытии кода.

runs полезны, когда ваши тесты PHPUnit разбиты на несколько комплектов, каждый из которых создает свой собственный отчет о покрытии — указание запусков как X означает, что последние X отчетов о покрытии, отправленные в Scrutinizer, будут объединены и обработаны как один . Это также полезно, когда вы тестируете несколько сред на Travis — например, PHP 5.5, 5.6 и 7.0 — если указать значение runs 3, эти отчеты будут объединены. Если runs опущены, только первый отчет о покрытии, полученный Scrutinizer, будет учтен для покрытия кода и статуса успешной сборки.

Конфигурация файла

Конфигурация на основе файлов считывается из файла .scrutinizer.yml из корневой папки вашего проекта. Он может содержать те же значения, что и все другие конфигурации, но имеет приоритет над ними — то есть значения в файле будут перезаписывать значения в конфигурации репо, которые будут перезаписывать значения в глобальной конфигурации.

Лига Скелет имеет один такой файл, и по умолчанию он готов к проверке Scrutinizer. Не стесняйтесь использовать их файл в качестве примера того, как создать свой собственный.

Локальная конфигурация

Локальная конфигурация может быть определена для каждого прогона, нажав «Проверка расписания», что позволит ввести пользовательские значения конфигурации, которые будут применены непосредственно перед прогоном, и только в этом одном прогоне:

Schedule Inspection Custom Config

Локальная конфигурация также является той, которую вы передаете через вызовы API в качестве параметров.

Эта конфигурация перезаписывает все остальные перед объединением.

Для удобной ссылки на эти перезаписи и иерархии конфигурации, а также полезные советы о том, когда использовать какой тип конфигурации, см. Эту удобную диаграмму .

Отчеты

Теперь, когда эта конфигурация не в порядке, давайте проверим реальный проект. Например, я буду использовать предыдущую версию моего клиента Diffbot, которую мы создали в предыдущей серии . После добавления его в Travis, настройки всего, как указано выше (с использованием идентичных параметров конфигурации), запускается сборка Scrutinizer.

Приборная доска

После завершения панель инструментов проекта изменится:

Панель инструментов проекта

Процесс сборки изначально считался неудачным из-за ошибки конфигурации с моей стороны, отсюда и ошибка.

Мы видим, что у нас очень хороший рейтинг по качеству кода, 100% тестированию и 4 обнаруженным проблемам. Давайте посмотрим, что это такое.

вопросы

Нажав на ссылку «4 проблемы» или на значок проблем в левом меню, мы попадаем в список проблем:

Экран проблем

Scrutinizer предлагает удобные теги для классификации проблем по типу и серьезности. Как ни странно, в столбце «Последние найденные» написано «2 месяца назад», несмотря на то, что проект был только что добавлен в Scrutinizer и первая проверка была запущена всего несколько минут назад. В некотором отношении этот интерфейс оставляет желать лучшего — было бы хорошо, например, если бы ошибки были закодированы цветом по степени важности, и если бы была опция «расширения», чтобы взглянуть на ошибки, не переходя на совершенно новый экран для незначительного вопроса.

Хорошо, тогда давайте посмотрим, в чем проблема. Я решил проверить вторую запись: Entity.php :

Сущность инспекции

Помимо того факта, что было бы хорошо иметь полный путь к файлу, напечатанный вверху, а не просто имя файла, этот интерфейс является чистым и очень прямым, чтобы указать на свои ошибки. В этом конкретном случае он на самом деле проверил докблок сигнатуры метода интерфейса и предупредил меня о его несоблюдении.

Действительно, однажды я изменил это:

Фиксированный код

к этому:

Код ошибки

и исправил аналогичную ошибку Api.php , я зафиксировал, нажал, и анализ был перезапущен, что дало положительный результат:

Уведомление об успехе

Он даже дал мне знать по электронной почте:

Уведомление об успехе по электронной почте

Оставшиеся две проблемы были не устранены из-за проблемы с анализатором Scrutinizer . Из-за их нефиксируемой природы игнорирование этих проблем было логичным подходом:

Скрыть вопросы

Это на самом деле не решает их, но скрывает их от списка проблем, чтобы они не выделялись в будущих проверках.

Код

Нажав на пункт меню «Код», мы попадаем на экран анализа кода, который говорит нам о качестве наших классов.

Экран качества кода

Класс Product кажется проблематичным. Посмотрим, на что жалуется Scrutinizer.

Анализ класса продукта

Ага. Так что это сложность, которая вызывает проблему? Хм, посмотрим «Как исправить».

Как исправить инструкции

Теперь, хотя мне очень нравится такой подход, как давать советы по ссылкам, просто ничего нельзя сделать для этого класса. Файл представляет собой одну большую коллекцию получателей, и нет никакого способа извлечь из него класс, подкласс или интерфейс. К сожалению, не существует способа игнорировать только эту инспекцию, как в случае с проблемами.

На экране «Код» есть еще одна ссылка, возможно, менее очевидная: «Горячие точки».

Горячие точки отображают наиболее «оптимизируемые» области кода — те, которые, как предполагает Scrutinizer, дадут наибольший прирост качества при наименьшем объеме работы:

Список горячих точек

В моем случае это был вышеупомянутый (нефиксированный) класс Product и два метода в абстрактном классе Api . Интересный. Давайте посмотрим на buildUrl метода buildUrl .

Проблемы метода BuildURL

Хм. Слишком много условий? Метод buildUrl берет различные параметры из API, который его вызывает, и создает из них URL-адрес, поэтому вполне естественно, что он имеет «много» управляющих структур. Можно извлечь циклы в такие методы, как buildFieldString и buildOptionsString , но зачем? Это единственный метод, который нуждается в построении строк, поэтому мне не нужно вносить дополнительные ненужные издержки, чтобы исправить это.

Другой метод, __construct безусловно, оставляет желать лучшего. Давайте улучшим это немного и изменим это от этого:

 public function __construct($url) { if (!is_string($url)) { throw new \InvalidArgumentException('URL param must be a string.'); } $url = trim($url); if (strlen($url) < 4) { throw new \InvalidArgumentException('URL must be at least four characters in length'); } if ($parts = parse_url($url)) { if (!isset($parts["scheme"])) { $url = "http://$url"; } } $filtered_url = filter_var($url, FILTER_VALIDATE_URL); if (false === $filtered_url) { throw new \InvalidArgumentException('You provided an invalid URL: ' . $url); } $this->url = $filtered_url; } 

к этому:

 public function __construct($url) { $url = trim((string)$url); if (strlen($url) < 4) { throw new \InvalidArgumentException( 'URL must be a string of at least four characters in length' ); } $url = (isset(parse_url($url)['scheme'])) ? $url : "http://$url"; $filtered_url = filter_var($url, FILTER_VALIDATE_URL); if (!$filtered_url) { throw new \InvalidArgumentException( 'You provided an invalid URL: ' . $url ); } $this->url = $filtered_url; } 

Теперь, если мы запустим перестроение путем фиксации и нажатия, мы получим следующее:

Панель инструментов показывает улучшения

Качество повысилось с B до A для метода __construct — успех!

Инспекции и статистика

Два оставшихся экрана — это «Инспекции», в которых перечислены все проведенные проверки и их результаты, и «Статистика и тренды», панель графиков, отображающая визуальные подсказки о том, как качество вашего кода прогрессирует (или ухудшается) с течением времени — я буду оставь это на усмотрение тебя.

Вывод

Scrutinizer — это мощный инструмент, обеспечивающий высочайшее качество вашего PHP-кода. Его очень легко настроить, и как только он запущен и работает, требуется минимальное взаимодействие, чтобы оставаться активным и быть в курсе событий. Хотя уровни ценообразования не слишком доступны для частных лиц и индивидуальных разработчиков с частными проектами (начиная с 50 евро, а не 19 евро, как указано на целевой странице), они очень доступны для компаний, и уровень бесплатного доступа более достаточно для проекта с открытым исходным кодом.

Вы пробовали Scrutinizer? Какие услуги качества кода вы используете? Может быть, их конкуренция, Code Climate? Дайте нам знать.