Перейти к содержанию

Baseline

Baseline -- это снимок всех текущих нарушений в вашем проекте. Когда baseline создан, Qualimetrix сообщает только о новых нарушениях -- всё, что уже было, молча игнорируется.

Зачем нужен baseline?

Когда вы добавляете Qualimetrix в существующий проект, первый запуск может показать сотни нарушений. Исправить их все сразу невозможно. Baseline позволяет:

  • Начать прямо сейчас -- внедрить Qualimetrix, не исправляя каждую legacy-проблему
  • Предотвращать новый долг -- каждое новое нарушение обнаруживается сразу
  • Отслеживать прогресс -- видеть, сколько старых нарушений вы уже исправили

Создание baseline

Запустите анализ с флагом --generate-baseline:

bin/qmx check src/ --generate-baseline=baseline.json

Это выполнит полный анализ и сохранит все нарушения в baseline.json. Файл содержит стабильные хеши для каждого нарушения, поэтому он работает даже при сдвиге номеров строк.

Совет

Коммитьте baseline.json в репозиторий. Так вся команда будет использовать один и тот же baseline.


Использование baseline

Передайте флаг --baseline при последующих запусках:

bin/qmx check src/ --baseline=baseline.json

Qualimetrix загружает baseline, выполняет анализ и показывает только нарушения, которых нет в baseline. Если вы добавили новое нарушение -- вы его увидите. Если исправили старое -- оно молча исчезнет из совпадений.


Как это работает

Каждое нарушение в baseline идентифицируется по:

  • Путь к файлу -- относительный путь к исходному файлу
  • Код нарушения -- идентификатор правила (например, complexity.cyclomatic.method)
  • Путь символа -- класс, метод или пространство имён, где возникло нарушение
  • Хеш содержимого -- стабильный хеш содержимого файла

При запуске с baseline Qualimetrix сопоставляет текущие нарушения с записями baseline. Если совпадение найдено, нарушение отфильтровывается.


Отслеживание прогресса с --show-resolved

Хотите узнать, сколько старых нарушений вы исправили? Используйте --show-resolved:

bin/qmx check src/ --baseline=baseline.json --show-resolved

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


Устаревшие записи

Запись baseline становится "устаревшей", когда файл, на который она ссылается, больше не существует (например, файл был удалён или переименован).

По умолчанию Qualimetrix сообщает об ошибке при обнаружении устаревших записей. У вас два варианта:

Вариант 1: Игнорировать устаревшие записи

bin/qmx check src/ --baseline=baseline.json --baseline-ignore-stale

Вариант 2: Очистить baseline

Удалить все устаревшие записи:

bin/qmx baseline:cleanup baseline.json

Совет

Запускайте baseline:cleanup периодически (например, после крупного рефакторинга), чтобы поддерживать файл baseline в чистоте.


Подавление в коде с @qmx-ignore

Для случаев, когда нарушение сделано намеренно и вы не хотите включать его в baseline, можно подавить его прямо в коде через комментарии.

Теги подавления работают во всех стилях комментариев:

  • PHPDoc-блоки: /** @qmx-ignore rule */
  • Строчные комментарии: // @qmx-ignore rule
  • Блочные комментарии: /* @qmx-ignore rule */

Ограничение

Inline-комментарии на одной строке с кодом не поддерживаются: $x = foo(); // @qmx-ignore rule не сработает. Размещайте комментарий на отдельной строке перед целевым кодом.

Подавление конкретного правила

class LegacyProcessor
{
    /**
     * @qmx-ignore complexity.cyclomatic Этот метод обрабатывает все legacy-форматы
     */
    public function process(array $data): array
    {
        // сложная, но намеренная логика
    }
}

Подавление всех правил для символа

/**
 * @qmx-ignore * Сгенерированный код, не анализировать
 */
class GeneratedMapper
{
    // ...
}

Подавление всех правил для всего файла

Добавьте docblock на уровне файла в его начале:

<?php
/**
 * @qmx-ignore-file
 */

class GeneratedCode
{
    // Все нарушения в этом файле подавлены
}

Подавление на следующей строке

Используйте @qmx-ignore-next-line в комментарии, чтобы подавить нарушение только на следующей строке:

class CliApplication
{
    public function run(): void
    {
        // обработка команд...

        // @qmx-ignore-next-line code-smell.exit Точка входа CLI
        exit(0);
    }
}

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

Также работает для подавления нарушений пустого catch:

try {
    $cache->delete($key);
} catch (CacheException) {
    // @qmx-ignore code-smell.empty-catch Кеширование best-effort
}

Синтаксис тегов подавления

Тег Область Пример
@qmx-ignore <правило> [причина] Символ, которому принадлежит комментарий @qmx-ignore complexity.cyclomatic Legacy-код
@qmx-ignore * [причина] Все правила для данного символа @qmx-ignore * Сгенерированный код
@qmx-ignore-next-line <правило> [причина] Только следующая строка @qmx-ignore-next-line code-smell.exit Точка входа CLI
@qmx-ignore-file Весь файл @qmx-ignore-file

Имя правила поддерживает сопоставление по префиксу: @qmx-ignore complexity подавляет все правила complexity.*.

Просмотр подавленных нарушений

Чтобы увидеть, что было подавлено:

bin/qmx check src/ --show-suppressed

Игнорирование тегов подавления

Чтобы запустить анализ так, как будто тегов @qmx-ignore нет:

bin/qmx check src/ --no-suppression

Переопределение порогов для символа с @qmx-threshold

Иногда классу или методу обоснованно нужны другие пороговые значения, чем установлены по умолчанию для проекта. Вместо полного подавления нарушения через @qmx-ignore можно переопределить конкретные пороги с помощью аннотации @qmx-threshold.

Переопределение порога для класса

/**
 * @qmx-threshold complexity.cyclomatic method.warning=20 method.error=40
 */
class ComplexStateMachine
{
    // Методы этого класса используют повышенные пороги сложности
}

Переопределение порога для метода

class OrderProcessor
{
    /**
     * @qmx-threshold complexity.cyclomatic warning=25 error=50
     * @qmx-threshold complexity.npath warning=500 error=2000
     */
    public function processLegacyOrder(array $data): Order
    {
        // Этот метод обрабатывает множество legacy edge cases
    }
}

Синтаксис

@qmx-threshold <правило> <опция>=<значение> [<опция>=<значение> ...]
  • Имя правила использует тот же формат с точками, что и конфигурация (complexity.cyclomatic, coupling.cbo и т.д.)
  • Опции используют те же ключи, что и YAML-конфигурация и CLI-флаг --rule-opt
  • На одном символе можно использовать несколько тегов @qmx-threshold для разных правил
  • Переопределения порогов действуют только на аннотированный символ -- они не распространяются на дочерние символы

Совет

Используйте @qmx-threshold, когда нарушение ожидаемо, но вы всё равно хотите, чтобы Qualimetrix контролировал какой-то лимит. Используйте @qmx-ignore, когда хотите полностью подавить нарушение.


Лучшие практики

1. Коммитьте baseline

git add baseline.json
git commit -m "chore: add Qualimetrix baseline"

Это гарантирует, что каждый член команды и CI-пайплайн используют один и тот же baseline.

2. Обновляйте baseline периодически

После исправления пачки нарушений перегенерируйте baseline:

bin/qmx check src/ --generate-baseline=baseline.json
git add baseline.json
git commit -m "chore: update Qualimetrix baseline (15 violations resolved)"

3. Используйте --show-resolved в CI

Добавьте --show-resolved в ваш CI-пайплайн для отслеживания прогресса:

bin/qmx check src/ --baseline=baseline.json --show-resolved --no-progress

4. Предпочитайте baseline вместо inline-подавления

Используйте @qmx-ignore для намеренных исключений (например, сгенерированный код, осознанные компромиссы). Используйте baseline для legacy-нарушений, которые вы планируете исправить.

5. Очищайте устаревшие записи после рефакторинга

bin/qmx baseline:cleanup baseline.json
git add baseline.json
git commit -m "chore: clean up stale baseline entries"

6. Экранируйте теги в документации

Если вы упоминаете @qmx-ignore или @qmx-threshold в docblock'ах как документацию (описания формата, примеры использования), оборачивайте их в обратные кавычки, чтобы парсер не интерпретировал их как настоящие теги:

/**
 * Используйте `@qmx-ignore complexity` для подавления правила.   // экранировано — не парсится
 * Используйте `@qmx-threshold complexity.cyclomatic 15`.          // экранировано — не парсится
 *
 * @qmx-ignore coupling Настоящий тег подавления                    // настоящий — будет распарсен
 */

Одиночная обратная кавычка без пары безопасна — тег будет распарсен как обычно.