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

Опции CLI

Qualimetrix предоставляет команду check для анализа кода и несколько вспомогательных команд для работы с baseline, git-хуками и визуализацией графа зависимостей.

Команда check

bin/qmx check [опции] [--] [<пути>...]

Аргумент paths

Укажите одну или несколько директорий или файлов для анализа:

# Анализ конкретных директорий
bin/qmx check src/ lib/

# Анализ одного файла
bin/qmx check src/Service/UserService.php

Если пути не указаны, Qualimetrix автоматически определит их из секции autoload вашего composer.json.


Опции файлов

--config, -c

Путь к YAML-файлу конфигурации:

bin/qmx check src/ --config=qmx.yaml

--exclude

Исключить директории из анализа. Можно указывать несколько раз:

bin/qmx check src/ --exclude=src/Generated --exclude=src/Legacy

Значение, не убравшее ни одного каталога, сообщается каналом discovery.unmatched-exclude — это warning на уровне проекта, а не отказ, и только на прогоне, чьи пути покрывают production-корни автозагрузки проекта. На более узком прогоне паттерн может не привязаться просто потому, что названный им код лежит вне среза.

--include-generated

По умолчанию Qualimetrix автоматически пропускает файлы, содержащие аннотацию @generated в первых 2 КБ. Этот флаг переопределяет это поведение и включает сгенерированные файлы в анализ:

bin/qmx check src/ --include-generated

Также можно задать в qmx.yaml:

include_generated: true

--suppress-path

Подавить нарушения для файлов, соответствующих glob-паттерну. Файлы по-прежнему анализируются (их метрики учитываются при расчёте метрик пространства имён), но нарушения не выводятся. Можно указывать несколько раз:

bin/qmx check src/ --suppress-path="src/Entity/*" --suppress-path="src/DTO/*"

Объединяется с suppress_paths из qmx.yaml — оба источника суммируются.

Не действует на правила architecture.*

Нарушения architecture.layer-violation и architecture.circular-dependency эта опция никогда не подавляет — почему и какие есть альтернативы, см. Подавление путей в отчёте.

--suppress-namespace

Подавить нарушения для классов в пространствах имён, соответствующих префиксу или glob-паттерну. Классы по-прежнему анализируются (их метрики учитываются в агрегированных расчётах), но нарушения не выводятся. Можно указывать несколько раз:

bin/qmx check src/ --suppress-namespace="App\Entity" --suppress-namespace="App\DTO\*"

Объединяется с suppress_namespaces из qmx.yaml — оба источника суммируются.

Не действует на правила architecture.*

Нарушения architecture.layer-violation и architecture.circular-dependency эта опция никогда не подавляет — почему и какие есть альтернативы, см. Подавление неймспейсов.


Опции пресетов

--preset

Применить именованный пресет или пользовательский YAML-файл. Можно указывать несколько раз или через запятую:

# Встроенные пресеты
bin/qmx check src/ --preset=strict
bin/qmx check src/ --preset=legacy

# Комбинирование пресетов (объединяются слева направо)
bin/qmx check src/ --preset=strict,ci
bin/qmx check src/ --preset=strict --preset=ci

# Пользовательский файл пресета
bin/qmx check src/ --preset=./my-preset.yaml

Доступные встроенные пресеты: strict, legacy, ci.

Пресеты применяются после автоопределения composer.json, но до qmx.yaml, поэтому ваш файл конфигурации всегда имеет приоритет. Подробности смотрите в разделе Конфигурация > Пресеты.


Опции вывода

--format, -f

Выбор формата вывода. По умолчанию: summary.

bin/qmx check src/ --format=json
bin/qmx check src/ --format=sarif

Доступные форматы: summary, text, text-verbose, json, metrics, checkstyle, sarif, gitlab, github, health, html, suppressed.

Подробности о каждом формате смотрите в разделе Форматы вывода.

--group-by

Группировка нарушений в выводе. Значение по умолчанию зависит от форматтера.

bin/qmx check src/ --format=text-verbose --group-by=rule

Доступные значения: none, file, rule, severity, class, namespace.

--format-opt

Передача специфичных для форматтера опций в формате key=value. Можно указывать несколько раз:

bin/qmx check src/ --format-opt=key=value

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

Опции формата JSON:

Опция По умолчанию Описание
violations=N\|all all Макс. кол-во нарушений в выводе (0=нет)
limit=N all Псевдоним для violations
top=N 10 Количество худших нарушителей
rank-by=count\|density count Переупорядочить списки худших нарушителей по количеству нарушений (по умолчанию) или по плотности нарушений
bin/qmx check src/ --format=json --format-opt=limit=100
bin/qmx check src/ --format=json --format-opt=violations=all
bin/qmx check src/ --format=json --format-opt=rank-by=density

Опции формата summary:

Опция По умолчанию Описание
top=N 3 Количество худших нарушителей
rank-by=count\|density count Переупорядочить списки худших нарушителей по количеству нарушений (по умолчанию) или по плотности нарушений
bin/qmx check src/ --format-opt=rank-by=density

Два несвязанных top

--format-opt=top=N (форматы JSON и summary) ограничивает списки худших пространств имён/классов. Глобальный флаг --top — другая опция: он ограничивает отдельный список «Top issues by impact». Их можно задавать независимо друг от друга.

Опции формата health:

Опция По умолчанию Описание
contributors=N 3 Сколько худших вкладчиков показывать для каждого измерения

Опции формата HTML:

Опция По умолчанию Описание
project-name=NAME автоопределение Переопределяет имя проекта в HTML-отчёте
bin/qmx check src/ --format=html --format-opt=project-name="My Project" -o report.html

--fail-on

Минимальный уровень нарушения, при котором возвращается ненулевой код выхода. По умолчанию: error.

# Поведение по умолчанию: ошибка только при error, предупреждения допускаются
bin/qmx check src/

# Ошибка и при warning (для строгого контроля качества)
bin/qmx check src/ --fail-on=warning

# Никогда не завершать с ошибкой из-за нарушений
bin/qmx check src/ --fail-on=none

Предупреждения по-прежнему отображаются в выводе, но по умолчанию не приводят к ненулевому коду завершения. Используйте --fail-on=warning, если хотите, чтобы предупреждения также блокировали CI.

Также можно задать в qmx.yaml:

fail_on: warning   # также ошибка при warning

--exclude-health

Исключить конкретные измерения здоровья из оценки. Исключённые измерения не отображаются в сводке здоровья и не влияют на общую оценку. Можно указывать несколько раз:

# Исключить типизацию из оценки здоровья
bin/qmx check src/ --exclude-health=typing

# Исключить несколько измерений
bin/qmx check src/ --exclude-health=typing --exclude-health=maintainability

Доступные измерения: complexity, cohesion, coupling, typing, maintainability.

Также можно задать в qmx.yaml:

exclude_health:
  - typing

--detail

Показать группированный список нарушений после сводки. Действует только на формат summary.

# Лимит по умолчанию (200 нарушений)
bin/qmx check src/ --detail

# Показать все нарушения (без лимита)
bin/qmx check src/ --detail=all

# Пользовательский лимит
bin/qmx check src/ --detail=50

Автоматически включается при использовании --namespace или --class.

--top

Количество самых значимых по влиянию находок. По умолчанию: 10; 0 отключает секцию.

# По умолчанию: топ-10
bin/qmx check src/

# Показать топ-25
bin/qmx check src/ --top=25

# Отключить секцию
bin/qmx check src/ --top=0

Управляет секцией «Top issues by impact» формата summary и ключом topIssues формата --format=json — списком находок, ранжированных по влиянию (сочетание ClassRank, серьёзности и времени на исправление), отдельным от списков худших пространств имён и худших классов. Больше ни один формат её не показывает.

Это другая опция, чем --format-opt=top=N, которая ограничивает списки худших нарушителей — см. таблицы опций форматов выше.

--all

Показать все нарушения без усечения. Сокращение для --format-opt=violations=all --detail=all.

# Все нарушения в формате JSON
bin/qmx check src/ --format=json --all

# Все нарушения в формате summary
bin/qmx check src/ --all

Не может быть объединён с --format-opt=violations=N (числовой лимит) — это вызовет ошибку. Совместное использование --all с --format-opt=violations=all допустимо (они синонимы).

--namespace

Фильтрация вывода по поддереву пространства имён. Значение — это паттерн пространства имён, а не буквальный префикс:

  • Без glob-символов сопоставление идёт по границам: App\Service совпадает с App\Service и всем, что под ним, но не с App\ServiceBus.
  • При наличии *, ? или [ значение трактуется как glob: App\*\Order выбирает App\Billing\Order и App\Sales\Order, а не пространство имён, буквально написанное со звёздочкой.
  • Завершающий \ косметический: App\Service\ и App\Service — один и тот же паттерн.
  • Пустое значение не совпадает ни с чем, включая глобальное пространство имён.
bin/qmx check src/ --namespace=App\\Service
bin/qmx check src/ --namespace='App\*\Order'

Фильтрует нарушения и худших нарушителей по выбранным пространствам имён. Показывает оценки здоровья поддерева. Автоматически включает --detail.

Находки уровня проекта (architecture.coverage-gap и прочие диагностики, судящие о прогоне целиком) не выбираются паттерном пространства имён никогда, включая *: они не принадлежат ни одному пространству имён.

То же правило сопоставления действует для drill-down по здоровью и списков худших нарушителей, которые включает эта опция, и для опции include_namespaces правила coupling.distance.

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

Взаимоисключающий с --class.

--class

Фильтрация вывода по конкретному классу с точным совпадением FQCN.

bin/qmx check src/ --class=App\\Service\\UserService

Фильтрует нарушения по указанному классу. Автоматически включает --detail.

FQCN, не совпавший ни с одним проанализированным классом, отвергается с кодом 3 по той же причине, что и --namespace: иначе пустой отчёт читается как чистый класс.

Взаимоисключающий с --namespace.


Опции кэширования

Qualimetrix кэширует разобранные AST-деревья для ускорения повторных запусков.

--no-cache

Полностью отключить кэширование:

bin/qmx check src/ --no-cache

--cache-dir

Указать директорию кэша. По умолчанию: .qmx-cache.

bin/qmx check src/ --cache-dir=/tmp/qmx-cache

Директория создаётся, если её нет. Путь, который не удаётся создать или в который нельзя писать, отвергается с кодом 3, а не выключает кэш молча; дверь закрывается так же во всех командах, разрешающих директорию кэша, а не только в check.

--clear-cache

Очистить кэш перед запуском анализа:

bin/qmx check src/ --clear-cache

Опции baseline

Полный жизненный цикл и формат файла описаны в Baseline.

--baseline=BASELINE

Использовать файл baseline, чтобы применить принятые потолки к текущим нарушениям:

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

--show-resolved

Посчитать записи, чья полная идентичность больше не появляется в измеряемом наборе:

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

Stale- и inert-записи сообщаются, но не завершают прогон ошибкой и не отключают другие записи baseline. Группа, которая всё ещё срабатывает с меньшим числом элементов, не считается resolved.

Lifecycle-команды baseline

Ниже приведена полная поверхность команд для записи и проверки baseline:

bin/qmx baseline:generate <baseline> [<paths>...] [--mode=MODE] [--force]
bin/qmx baseline:update   <baseline> [<paths>...] [--force]
bin/qmx baseline:cleanup  <baseline> [<paths>...] [--remove=REMOVE]... [--force]
bin/qmx baseline:explain  <symbol> [<paths>...] [--baseline=BASELINE] [--channel=CHANNEL]
bin/qmx baseline:rename-channels <baseline> <map> [--format=FORMAT]

Первые четыре команды принимают --config=CONFIG, --preset=PRESET, --disable-rule=DISABLE-RULE, --only-rule=ONLY-RULE и --rule-opt=RULE-OPT. Ни одна не принимает опции исключения или suppression. baseline:rename-channels не принимает ни одной из них: она не запускает анализ, поэтому измеряемого набора, который они определяли бы, нет.

  • baseline:generate захватывает текущие измеряемые нарушения. По умолчанию используется --mode=ratchet; --mode=suppress записывает безусловное принятие захваченных идентичностей. Его --force перезаписывает существующий файл.
  • baseline:update только ужесточает существующие записи. Его --force снимает проверку покрытия записанной области.
  • baseline:cleanup по умолчанию выводит кандидатов и удаляет только повторяемые селекторы --remove=REMOVE. Его --force также снимает проверку области.
  • baseline:explain показывает порог из конфигурации, принятую величину baseline и override из исходника для канонического символа; --channel=CHANNEL сужает ответ.
  • baseline:rename-channels переписывает поле channel записей, названных объявленной табличной картой, и больше ничего, не анализируя код. Код 1 покрывает и отказ по содержимому, и недоступный файл baseline или карты; 2 — некорректное значение --format. В обоих случаях baseline остаётся побайтово неизменным, а сам отказ сообщается в выбранном формате — при --format=json объектом с ключом error. См. Перенос baseline на переименованные каналы — учти, что перенос записи меняет её селектор.

Четыре анализирующие команды отказываются интерпретировать или записывать baseline при неполном анализе и завершаются с кодом 4. --force снимает только ограничения файла/области; он не делает частичный набор измерений допустимым. Существующий файл остаётся побайтово неизменным, а baseline:generate не создаёт отсутствующий файл.

Загружаемые версии baseline и процедура миграции старого файла описаны в разделе Замена старого baseline.

Удалённые опции --generate-baseline и --baseline-ignore-stale не имеют алиасов. Используй вместо них baseline:generate и явный baseline:cleanup --remove.


Опции подавления

--show-suppressed

Показать нарушения, подавленные тегами @qmx-ignore, а также нарушения, подавленные записью suppress_namespaces / suppress_namespace_channels / suppress_paths на уровне правила в qmx.yaml (см. «Правила»):

bin/qmx check src/ --show-suppressed

Независимо от --show-suppressed, запуск с -v печатает разбивку по правилам — сколько нарушений подавлено таким образом. Namespace-бакет включает обе опции неймспейсов и выводится отдельно от suppress_paths; каждый бакет разбит по имени правила. В отличие от @qmx-ignore, в остальном это подавление проходит незаметно — ничто в стандартном выводе не сигнализирует о том, что оно произошло.

--show-suppressed выводит прозой лишь часть этого. --format=suppressed публикует полный состав — все семь механизмов подавления, а не только эти два, — как машиночитаемый JSON; см. «Форматы вывода». Для взведения per-rule-захвата достаточно либо --show-suppressed, либо выбора --format=suppressed (в том числе format: suppressed в qmx.yaml) — оба вместе не нужны. В остальном эти две поверхности не эквивалентны — что показывает каждая, см. в разделе suppressed.

Подавление — закрытое множество из семи механизмов. Несколько соседних решений тоже делают находку невидимой, но подавлением не являются, и ни одна из поверхностей их не покрывает: правило, которое вообще не исполнялось (--disable-rule, --only-rule, enabled: false), не породило находку, которую можно было бы подавить; отключённый канал для правила без класса (виден в qmx rules) снимается тем же способом, ещё до леджера; порог, из-за которого находка вообще не родилась (@qmx-threshold), проверяется отдельным аудитом, а не через эту поверхность; усечение форматтером (--detail, violations=N) оставляет находку в payload и лишь помечает её truncated; а сужение вывода --namespace/--class меняет только представление конкретного запуска, ничего не убирая из самого результата.

--no-suppression-annotations

Выводить все нарушения, включая те, которые подавлены тегами @qmx-ignore:

bin/qmx check src/ --no-suppression-annotations

Опция не меняет то, что измеряет baseline

Флаг влияет только на отчёт. Baseline измеряет те нарушения, которые оставляют конфигурация и аннотации в исходниках, поэтому нарушение, убранное тегом @qmx-ignore, никогда не попадает в baseline и никогда не сравнивается с ним — независимо от того, передан ли этот флаг.

Видимое следствие: под этим флагом подавленное аннотацией нарушение показывается со своей собственной серьёзностью и никогда не повышается до ошибки, потому что ни одна запись baseline его не покрывает. Флаг может сузить измеряемое baseline множество (--suppress-path, --suppress-namespace), но расширить его не может ни один.


Опции области Git

Вывод нарушений только для изменённых файлов. Полное руководство смотрите в разделе Интеграция с Git.

--report

Управление тем, какие нарушения выводить. Анализирует весь проект, но показывает только нарушения из изменённых файлов:

bin/qmx check src/ --report=git:main..HEAD
bin/qmx check src/ --report=git:origin/develop..HEAD

--report-strict

В режиме diff показывать нарушения только из самих изменённых файлов. Без этого флага также выводятся нарушения из родительских пространств имён:

bin/qmx check src/ --report=git:main..HEAD --report-strict

Опции выполнения

--workers, -w

Управление параллельной обработкой. По умолчанию: автоопределение по количеству CPU.

# Отключить параллельную обработку (один процесс)
bin/qmx check src/ --workers=1

# Отключить параллельную обработку (последовательно)
bin/qmx check src/ --workers=0

# Использовать ровно 4 воркера
bin/qmx check src/ --workers=4

Совет

Используйте --workers=1 для отладки или в однопроцессном окружении. --workers=0 отключает параллелизм (последовательное выполнение); автоопределение — это поведение по умолчанию, когда опция не задана.

--memory-limit

Установить лимит памяти PHP для анализа. По умолчанию используется значение memory_limit из php.ini.

# Установить лимит памяти 1ГБ для больших проектов
bin/qmx check src/ --memory-limit=1G

# Без ограничений памяти
bin/qmx check src/ --memory-limit=-1

Допустимые форматы: -1 (без ограничений) или положительное целое число с опциональным суффиксом K/M/G (например, 512M, 2G).

Эквивалент в YAML: memory_limit: 1G

--log-file

Записывать отладочный лог в файл:

bin/qmx check src/ --log-file=qmx.log

--log-level

Установить минимальный уровень логирования. По умолчанию: info.

bin/qmx check src/ --log-file=qmx.log --log-level=debug

Доступные уровни: debug, info, warning, error. Значение вне этого набора отвергается с кодом 3, а не откатывается к info.

--no-progress

Отключить прогресс-бар. Полезно в CI-пайплайнах:

bin/qmx check src/ --no-progress

Принимается каждой командой, которая показывает прогресс-бар: check, directives, debug:layer-assignment, baseline:generate, baseline:update, baseline:cleanup и baseline:explain. graph:export тоже анализирует дерево, но бара не рисует, поэтому опции у него нет.

Прогресс-бар пишется в поток ошибок, поэтому отчёт в стандартном выводе остаётся машиночитаемым даже на терминале — bin/qmx check src/ --format=json > report.json даёт валидный JSON и без этого флага. Бар рисуется, только если поток ошибок — терминал; перенаправление потока ошибок гасит его, не трогая отчёт.

Бар делит поток ошибок с подробным логом (-v, -vv, -vvv) и с предупреждениями во время прогона. И то и другое рисуется через одного владельца: строка диагностики сдвигает бар вниз и остаётся на экране, а бар перерисовывается под ней. Поэтому повышение подробности бар не выключает, а бар не съедает строки лога.

--silent, -q/--quiet

Флаги Symfony Console, подавляющие обычный вывод. Оба принимаются любой командой:

bin/qmx check src/ --silent
bin/qmx check src/ -q

--silent больше не гарантирует ноль байт на любом коде возврата

--silent и -q/--quiet сейчас ведут себя одинаково: оба подавляют отчёт в стандартном выводе, но отказ из-за ошибки конфигурации или входных данных (например, несуществующий путь) всё равно пишется в stderr. Прогон, отклонённый до начала анализа, даёт 0 байт на stdout и человекочитаемую строку ошибки на stderr — независимо от того, какой из двух флагов передан:

bin/qmx check src/DoesNotExist --silent
# код возврата 3, пустой stdout, сообщение об ошибке в stderr

Обёртка CI, построенная на прежнем допущении «--silent значит ноль вывода при любом коде возврата», увидит этот текст в stderr при отказе. Перенаправьте и stderr тоже (--silent 2>/dev/null), если это допущение обязательно должно выполняться.


Опции профилирования

--profile

Включить внутренний профайлер. Опционально можно указать файл для сохранения профиля:

<!-- llms:skip-end -->

# Показать сводку профилирования на экране
bin/qmx check src/ --profile

# Сохранить профиль в файл
bin/qmx check src/ --profile=profile.json

--profile-format

Выбор формата экспорта профиля. По умолчанию: json.

bin/qmx check src/ --profile=profile.json --profile-format=chrome-tracing

Доступные форматы: json, chrome-tracing.

Совет

Используйте формат chrome-tracing и откройте файл в Chrome DevTools (chrome://tracing) для визуального анализа производительности.


Опции правил

--disable-rule

Отключить правило-производитель, целую группу или отдельный канал нарушения. Селектор — это либо точное имя (правило-производитель, группа вроде complexity или канал), либо X.* строго для потомков X — сам X в это не входит. Голый префикс без звёздочки — ошибка. Селектор канала можно сузить до одного уровня дерева агрегации через :level, как и у --only-rule. Отключение одного канала не останавливает производителя, чтобы остальные его каналы продолжали попадать в отчёт. Опцию можно указывать несколько раз:

# Отключить одно правило
bin/qmx check src/ --disable-rule=size.class-count

# Отключить все правила сложности
bin/qmx check src/ --disable-rule=complexity.*

# Отключить несколько
bin/qmx check src/ --disable-rule=complexity.* --disable-rule=cohesion.lcom

# Отключить только один канал computed finding
bin/qmx check src/ --disable-rule=health.complexity

Оптимизация памяти

Отключение правила duplication.clone также полностью пропускает ресурсоёмкую фазу обнаружения дубликатов. На больших кодовых базах (500+ файлов) это может значительно снизить потребление памяти. Используйте --disable-rule=duplication.clone, если возникают ошибки нехватки памяти. Написание с уровнем — --disable-rule=duplication.clone:project — пропускает её так же: канал сообщает ровно на этом уровне, поэтому погасить уровень значит погасить правило. Производитель останавливается, как только селекторы отключения вместе накрывают каждый уровень каждого его канала; один уровень двухуровневого канала оставляет его работать, потому что второму уровню ещё есть о чём сообщить.

--only-rule

Запустить только подходящие правила-производители или каналы нарушений. Селектор — это либо точное имя (правило-производитель, группа вроде complexity или канал), либо X.* строго для его потомков; каждое из них можно сузить до одного уровня дерева агрегации через :level. Селектор с уровнем не останавливает своего производителя: отфильтрованный производитель никогда не выдал бы запрошенный уровень. Опцию можно указывать несколько раз:

# Запустить только правила сложности
bin/qmx check src/ --only-rule=complexity.*

# Запустить два конкретных правила
bin/qmx check src/ --only-rule=complexity.ccn --only-rule=size.method-count

# Выбрать один канал встроенного измерения здоровья: производитель и канал
# называются одинаково, потому что каждое из шести измерений — сам себе производитель
bin/qmx check src/ --only-rule=health.complexity

Селектор должен точно совпасть с зарегистрированным producer, группой или выводимым каналом, либо X.* должен разрешиться хотя бы в одного потомка. Неизвестный селектор — включая голый префикс без звёздочки или X.*, не совпавший ни с чем, — завершается с кодом 3 до записи report-payload в stdout:

Rule selector "complexity" does not match any registered producer, group, or channel.

Аналогично, владелец перед : в --rule-opt=RULE:OPTION=VALUE должен быть точным producer-rule, а не группой или каналом — группа или канал здесь являются ошибкой. То же правило действует и для ключей секции rules: в YAML.

Отбору подчиняется каждый канал, включая собираемый последним

annotation.unused-directive — вердикт «это подавление ничего не погасило» — можно вынести только после того, как все прочие правила выдали свои находки, поэтому прогон собирает его после исполнения правил. Тем не менее он отбирается как любой другой канал: --disable-rule=annotation.unused-directive (или annotation.unused-directive:file) гасит его, а --only-rule, назвавший другие каналы annotation.directive, но не назвавший этот, его не публикует.

Опции исключений, ключёванные продюсером, — отдельный вопрос, и до этого канала они не достают: rules.annotation.directive.suppress_paths действует только на его ранние каналы, а suppress_namespaces не действует ни на один из них, поскольку эти находки сообщаются о файле, в котором написана аннотация.

--rule-opt

Переопределить опции правил из командной строки. Формат: rule-name:option=value, где rule-name должен быть точным producer-rule — никогда группой, никогда каналом и никогда wildcard. Это то же ограничение, что действует для владельца перед : в --only-rule/--disable-rule и для ключей секции rules: в YAML. Можно указывать несколько раз:

bin/qmx check src/ --rule-opt=complexity.ccn:callable.warning=15
bin/qmx check src/ --rule-opt=complexity.ccn:callable.error=30

Все три способа ошибиться отвергаются с кодом 3 там, где раньше пара опций молча отбрасывалась: значение, записанное без =VALUE; имя правила, которому не отвечает ни один зарегистрированный producer; и имя опции, которого это правило не принимает. В последнем случае отказ перечисляет опции, которые правило принимает.

suppress_namespace_channels настраивается в YAML, а не через --rule-opt: каждому селектору нужен непустой список паттернов неймспейсов, тогда как --rule-opt передаёт скалярные значения. Его ключи — это селекторы каналов, подчиняющиеся тому же правилу «точное имя или X.*», что и @qmx-ignore: голый префикс вроде health теперь ошибка, а не сокращение для health.*. Ключ может добавить :namespace и никакой другой уровень: опции достаются только агрегаты по неймспейсам, поэтому любой другой уровень назвал бы фильтр, который не сработает никогда.

Быстрые флаги для правил

Для многих правил доступны специальные CLI-флаги для быстрой настройки опций:

Флаг Правило Опция
--cyclomatic-warning=N complexity.ccn callable.warning
--cyclomatic-error=N complexity.ccn callable.error
--cyclomatic-class-warning=N complexity.ccn class.max_warning
--cyclomatic-class-error=N complexity.ccn class.max_error
--cognitive-warning=N complexity.cognitive callable.warning
--cognitive-error=N complexity.cognitive callable.error
--cognitive-class-warning=N complexity.cognitive class.max_warning
--cognitive-class-error=N complexity.cognitive class.max_error
--npath-warning=N complexity.npath callable.warning
--npath-error=N complexity.npath callable.error
--npath-class-warning=N complexity.npath class.max_warning
--npath-class-error=N complexity.npath class.max_error
--wmc-warning=N complexity.wmc warning
--wmc-error=N complexity.wmc error
--wmc-exclude-data-classes complexity.wmc excludeDataClasses
Флаг Правило Опция
--cbo-warning=N coupling.cbo class.warning
--cbo-error=N coupling.cbo class.error
--cbo-ns-warning=N coupling.cbo namespace.warning
--cbo-ns-error=N coupling.cbo namespace.error
--distance-warning=N coupling.distance max_distance_warning
--distance-error=N coupling.distance max_distance_error
--instability-class-warning=N coupling.instability class.max_warning
--instability-class-error=N coupling.instability class.max_error
--instability-ns-warning=N coupling.instability namespace.max_warning
--instability-ns-error=N coupling.instability namespace.max_error
--class-rank-warning=N coupling.class-rank warning
--class-rank-error=N coupling.class-rank error
Флаг Правило Опция
--class-count-warning=N size.class-count warning
--class-count-error=N size.class-count error
--method-count-warning=N size.method-count warning
--method-count-error=N size.method-count error
--property-count-warning=N size.property-count warning
--property-count-error=N size.property-count error
Флаг Правило Опция
--dit-warning=N design.dit warning
--dit-error=N design.dit error
--lcom-warning=N cohesion.lcom warning
--lcom-error=N cohesion.lcom error
--lcom-min-methods=N cohesion.lcom minMethods
--lcom-exclude-readonly cohesion.lcom excludeReadonly
--lcom-exclude-methods=NAME cohesion.lcom excludeMethods
--noc-warning=N design.noc warning
--noc-error=N design.noc error
--param-type-coverage-warning=N design.type-coverage.param warning
--param-type-coverage-error=N design.type-coverage.param error
--return-type-coverage-warning=N design.type-coverage.return warning
--return-type-coverage-error=N design.type-coverage.return error
--property-type-coverage-warning=N design.type-coverage.property warning
--property-type-coverage-error=N design.type-coverage.property error
--property-exclude-readonly size.property-count excludeReadonly
--property-exclude-promoted-only size.property-count excludePromotedOnly
Флаг Правило Опция
--mi-warning=N maintainability.mi warning
--mi-error=N maintainability.mi error
--mi-min-statements=N maintainability.mi minStatements
--mi-exclude-tests maintainability.mi excludeTests
Флаг Правило Опция
--constructor-overinjection-warning=N code-smell.constructor-overinjection warning
--constructor-overinjection-error=N code-smell.constructor-overinjection error
--data-class-woc-threshold=N design.data-class wocThreshold
--data-class-wmc-threshold=N design.data-class wmcThreshold
--data-class-min-members=N design.data-class minMembers
--data-class-exclude-readonly design.data-class excludeReadonly
--data-class-exclude-promoted-only design.data-class excludePromotedOnly
--data-class-exclude-exceptions design.data-class excludeExceptions
--god-class-wmc-threshold=N design.god-class wmcThreshold
--god-class-lcom-threshold=N design.god-class lcomThreshold
--god-class-tcc-threshold=N design.god-class tccThreshold
--god-class-class-loc-threshold=N design.god-class classLocThreshold
--god-class-min-criteria=N design.god-class minCriteria
--god-class-min-methods=N design.god-class minMethods
--god-class-exclude-readonly design.god-class excludeReadonly
--long-parameter-list-warning=N code-smell.long-parameter-list warning
--long-parameter-list-error=N code-smell.long-parameter-list error
--long-parameter-list-vo-warning=N code-smell.long-parameter-list vo-warning
--long-parameter-list-vo-error=N code-smell.long-parameter-list vo-error
--unreachable-code-warning=N code-smell.unreachable-code warning
--unreachable-code-error=N code-smell.unreachable-code error
Флаг Правило Опция
--circular-deps architecture.circular-dependency enabled
--max-cycle-size=N architecture.circular-dependency maxCycleSize
--layer-violation architecture.layer-violation enabled
--layer-violation-severity=SEVERITY architecture.layer-violation severity
--unassigned-class-mode=MODE architecture.unassigned-class mode

Другие команды

baseline:cleanup

Проверить stale-кандидатов в baseline. Без --remove команда только выводит их и никогда не меняет файл; удалить явно проверенный selector можно так, как описано в Baseline:

bin/qmx baseline:cleanup baseline.json src/
bin/qmx baseline:cleanup baseline.json src/ --remove=<selector>

debug:layer-assignment

Показать, к какому слою архитектуры отнесён класс, и перечислить все остальные слои, чьи критерии тоже совпали бы (потенциальный источник затенения). Полное описание — в разделе Инспекция назначения слоя для одного класса.

bin/qmx debug:layer-assignment 'App\Service\Foo'
bin/qmx debug:layer-assignment 'App\Service\Foo' --config qmx.yaml

# Машиночитаемый вывод — для агентов и скриптов, не для парсинга текстового отчёта
bin/qmx debug:layer-assignment 'App\Service\Foo' --format=json
Опция Описание
-c, --config=FILE Путь к qmx.yaml (по умолчанию: qmx.yaml в текущей директории)
--format=FORMAT text (по умолчанию) или json

--format=json сериализует тот же результат разрешения, что рендерит текстовый отчёт. Команда отвечает только про классы, которые вошли в прогон: FQN, не соответствующий ни одной разобранной декларации — опечатка или класс, не попавший в прогон из-за paths, exclude либо фильтра сгенерированных файлов, — завершается кодом 3 с конвертом ошибки, а не классифицируется. Схема:

{
  "fqn": "App\\Service\\Foo",
  "assigned": { "layer": "any-foo", "criteria": ["pattern \"App\\**\\Foo\""] },
  "shadowed": [
    { "layer": "service", "criteria": ["pattern \"App\\Service\\**\""] }
  ],
  "hasLayers": true
}
  • assignednull, если ни один слой не совпал (в этом случае shadowed пуст).
  • shadowed перечисляет все остальные совпавшие слои в порядке объявления — каждый из них получил бы класс, будь он объявлен раньше assigned.
  • hasLayers различает «слои не объявлены» (false) и «слои объявлены, но ни один не совпал с этим классом» (true при assigned: null).
  • При ошибке --format=json печатает в stdout {"error": "...", "exit_code": N} вместо человекочитаемой строки <error>; неизвестное значение --format завершается кодом 3 независимо от формата.

directives

Показать, что на самом деле делает каждая инлайновая директива @qmx-ignore и @qmx-threshold в анализируемом дереве. Подавление оценивается по тому, что оно погасило; пороговая директива — снятием и повторным исполнением правил поверх измерений того же прогона, по умолчанию только того правила, которое она адресует, — одно исполнение на директиву.

bin/qmx directives src/

# Переисполнить все включённые правила, а не только адресуемое — контроль, которым проверяется узкий проход по умолчанию
bin/qmx directives src/ --sweep=full

# Машиночитаемый вывод — для агентов, скриптов и CI
bin/qmx directives src/ --format=json
Опция Описание
-c, --config=FILE Путь к qmx.yaml (по умолчанию qmx.yaml в текущем каталоге)
--format=FORMAT text (по умолчанию) или json
--sweep=SCOPE Сколько правил переисполняет каждая контрфактическая проверка: narrow (по умолчанию) или full
--preset=PRESET Применить именованный пресет (можно повторять)
--only-rule=RULE Судить по прогону, в котором работали только эти правила (можно повторять)
--disable-rule=RULE Судить по прогону с выключенными правилами (можно повторять)
--rule-opt=RULE:OPT=VAL Судить по прогону с этой опцией правила (можно повторять)

Четыре опции селекции нужны потому, что вердикт относителен прогону: указывайте те же правила и границы, с которыми проверяет ваш CI, иначе ответ будет про другой прогон.

@qmx-threshold называет ровно одно правило, поэтому при --sweep=narrow контрфактическая проверка переисполняет только его. --sweep=full переисполняет все включённые правила ради тех же вердиктов, но заметно дороже — это не медленный запасной вариант, а контроль, которым измеряется, а не предполагается, что снятие директивы одного правила не может сдвинуть находки другого: оба охвата прогоняются по одному дереву и сравниваются вердикт к вердикту. На собственном src/ этого проекта узкий охват в несколько раз дешевле, и оба охвата совпадают по каждому вердикту. И текстовый отчёт, и --format=json указывают, каким охватом получены вердикты.

Коды возврата: 0 — инертных нет, 2 — найдена хотя бы одна инертная директива с наблюдаемой границей, 3 — негодный ввод или ошибка конфигурации, включая охват, в котором не проанализировано ни одного PHP-файла (каталог без PHP, exclude, поглотивший всё, или одни только @generated-файлы), 4 — прогон не разобрал часть дерева, 1 — сама команда неожиданно упала.

Вердиктов четыре, из них три — ответы, а один — отсутствие ответа:

Вердикт Что он утверждает
effective Снятие директивы меняет то, что производят правила.
applied-boundary-only Директива применилась, и не сдвинулось ничего, кроме напечатанной ею границы.
inert Снятие не меняет ничего. Единственный вердикт, который двигает код возврата.
unmeasured Ответа нет, и отчёт называет причину: продюсер не исполнялся, директива уже отклонена другим каналом, у неё нет фильтра правил, либо тот же субъект перекрыт другой директивой того же правила.

Вердикт относителен анализируемому охвату

Порог на метрике, вычисляемой по проанализированному подграфу, — прежде всего связность — бывает живым по всему проекту и мёртвым по одному его каталогу, и оба ответа верны. Указывайте команде то, что проект действительно анализирует. Отчёт печатает охват, в котором он измерял, а прогон, не разобравший часть дерева, возвращает 4 вместо того, чтобы называть что-либо мёртвым.

Судим по произведённому правилами, а не по отчёту

suppress_paths, suppress_namespaces и suppress_namespace_channels подавляют публикацию, а не измерение. Директива, сдвинувшая находку внутри исключённого неймспейса, всё равно что-то сделала, поэтому аудит задаёт вопрос по всем находкам, произведённым правилами, а не по отчёту. Единственный канал вне этого универсума — annotation.unused-directive, который прогон собирает уже после исполнения правил: адресовать его директива не может, поэтому и судить по нему нечего.

Единственное, что подавлению не засчитывается, — гашение ошибки конфигурации (annotation.unresolved-directive и два его собрата). Эти каналы выведены из-под аннотационного подавления по построению, а не настройкой, поэтому директива, адресующая любой из них, отчитывается инертной, как бы она ни была написана.

annotation.unused-directive исключён громче: директиву, адресующую его, аудит не судит, а сообщает unmeasured / already-refused — тот же ответ, который check печатает как annotation.unresolved-directive на этой строке.

Вердикт applied-boundary-only намеренно ничего не утверждает о направлении. У слоя правил нет понятия «строже»: у coupling.instability хуже больше, у cohesion.tcc меньше, — поэтому директива, ужесточающая границу, и директива, поднявшая границу, которую величина уже прошла, дают одно и то же наблюдение. В --format=json этот вердикт сохраняет стабильный ключ overrun.

Если правило не публикует границу вместе с находкой, вердикт inert сопровождается пометкой об этом и не роняет сборку: граница, которую величина уже прошла, выглядела бы точно так же, и требовать удаления директивы значило бы выдать незаданный вопрос за доказанный долг. В --format=json это поле "boundary_observable": false.

При ошибке --format=json печатает в stdout {"error": "...", "exit_code": N} вместо человекочитаемой строки <error>.

graph:export

Экспортировать граф зависимостей для визуализации:

# Экспорт в формате DOT (по умолчанию)
bin/qmx graph:export src/ -o graph.dot

# Экспорт в формате JSON (агрегированный список смежности с метаданными)
bin/qmx graph:export src/ --format=json -o graph.json

# Фильтрация по пространству имён
bin/qmx graph:export src/ --namespace=App\\Service --namespace=App\\Repository

# Исключение пространств имён
bin/qmx graph:export src/ --exclude-namespace=App\\Generated

# Изменение направления графа
bin/qmx graph:export src/ --direction=TB

# Отключение группировки по пространствам имён
bin/qmx graph:export src/ --no-clusters
Опция Описание
-o, --output=FILE Выходной файл (по умолчанию: stdout)
-f, --format=FORMAT dot (по умолчанию) или json
-d, --direction=DIR Направление графа: LR, TB, RL, BT (по умолчанию: LR)
--no-clusters Не группировать узлы по пространствам имён
--namespace=NS Включить только указанные пространства имён (можно повторять)
--exclude-namespace=NS Исключить указанные пространства имён (можно повторять)

Значение --namespace, не совпавшее ни с одной вершиной, отвергается с кодом 3, а не экспортирует пустой граф. --exclude-namespace намеренно сохраняет молчание: промахнувшееся исключение оставляет картину целой, и смотрящий ничего не теряет.

Если хотя бы один обнаруженный файл не удалось разобрать или обработать, graph:export завершается с кодом 4 и не выводит частичный граф. Команда не создаёт отсутствующий output-файл и побайтово сохраняет существующий.

hook:install

Установить git-хук pre-commit:

bin/qmx hook:install

# Перезаписать существующий хук
bin/qmx hook:install --force

hook:status

Показать текущий статус хука pre-commit:

bin/qmx hook:status

hook:uninstall

Удалить хук pre-commit:

bin/qmx hook:uninstall

# Восстановить оригинальный хук из резервной копии
bin/qmx hook:uninstall --restore-backup

rules

Вывести список всех доступных правил с описаниями и опциями CLI:

# Показать все правила
bin/qmx rules

# Фильтр по группе
bin/qmx rules --group=complexity

Пример вывода (для --group=complexity):

4 rules available

Complexity
  complexity.cognitive                     Checks cognitive complexity at method and class levels
    --cognitive-warning (--rule-opt=complexity.cognitive:callable.warning=...)
    --cognitive-error (--rule-opt=complexity.cognitive:callable.error=...)
    --cognitive-class-warning (--rule-opt=complexity.cognitive:class.max_warning=...)
    --cognitive-class-error (--rule-opt=complexity.cognitive:class.max_error=...)
  complexity.ccn                    Checks cyclomatic complexity at method and class levels
    --cyclomatic-warning (--rule-opt=complexity.ccn:callable.warning=...)
    --cyclomatic-error (--rule-opt=complexity.ccn:callable.error=...)
    --cyclomatic-class-warning (--rule-opt=complexity.ccn:class.max_warning=...)
    --cyclomatic-class-error (--rule-opt=complexity.ccn:class.max_error=...)
  ...

Usage: bin/qmx check --disable-rule=<name> | --only-rule=<name>
        bin/qmx check --rule-opt=<name>:<option>=<value>

Правила сгруппированы по категориям, рядом с каждым CLI-алиасом показана длинная форма --rule-opt, в которую он разворачивается. Значений порогов по умолчанию в этом выводе нет — они описаны в Пороговых значениях по умолчанию.