Опции CLI¶
Qualimetrix предоставляет команду check для анализа кода и несколько вспомогательных команд для работы с baseline, git-хуками и визуализацией графа зависимостей.
Команда check¶
Аргумент paths¶
Укажите одну или несколько директорий или файлов для анализа:
# Анализ конкретных директорий
bin/qmx check src/ lib/
# Анализ одного файла
bin/qmx check src/Service/UserService.php
Если пути не указаны, Qualimetrix автоматически определит их из секции autoload вашего composer.json.
Опции файлов¶
--config, -c¶
Путь к YAML-файлу конфигурации:
--exclude¶
Исключить директории из анализа. Можно указывать несколько раз:
Значение, не убравшее ни одного каталога, сообщается каналом
discovery.unmatched-exclude — это warning на
уровне проекта, а не отказ, и только на прогоне, чьи пути покрывают
production-корни автозагрузки проекта. На более узком прогоне паттерн может не
привязаться просто потому, что названный им код лежит вне среза.
--include-generated¶
По умолчанию Qualimetrix автоматически пропускает файлы, содержащие аннотацию @generated в первых 2 КБ. Этот флаг переопределяет это поведение и включает сгенерированные файлы в анализ:
Также можно задать в qmx.yaml:
--suppress-path¶
Подавить нарушения для файлов, соответствующих glob-паттерну. Файлы по-прежнему анализируются (их метрики учитываются при расчёте метрик пространства имён), но нарушения не выводятся. Можно указывать несколько раз:
Объединяется с suppress_paths из qmx.yaml — оба источника суммируются.
Не действует на правила architecture.*
Нарушения architecture.layer-violation и architecture.circular-dependency эта опция
никогда не подавляет — почему и какие есть альтернативы, см.
Подавление путей в отчёте.
--suppress-namespace¶
Подавить нарушения для классов в пространствах имён, соответствующих префиксу или glob-паттерну. Классы по-прежнему анализируются (их метрики учитываются в агрегированных расчётах), но нарушения не выводятся. Можно указывать несколько раз:
Объединяется с 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.
Доступные форматы: summary, text, text-verbose, json, metrics, checkstyle, sarif, gitlab, github, health, html, suppressed.
Подробности о каждом формате смотрите в разделе Форматы вывода.
--group-by¶
Группировка нарушений в выводе. Значение по умолчанию зависит от форматтера.
Доступные значения: none, file, rule, severity, class, namespace.
--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 | Переупорядочить списки худших нарушителей по количеству нарушений (по умолчанию) или по плотности нарушений |
Два несвязанных top
--format-opt=top=N (форматы JSON и summary) ограничивает списки худших
пространств имён/классов. Глобальный флаг --top — другая опция:
он ограничивает отдельный список «Top issues by impact». Их можно задавать
независимо друг от друга.
Опции формата health:
| Опция | По умолчанию | Описание |
|---|---|---|
contributors=N |
3 | Сколько худших вкладчиков показывать для каждого измерения |
Опции формата HTML:
| Опция | По умолчанию | Описание |
|---|---|---|
project-name=NAME |
автоопределение | Переопределяет имя проекта в 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:
--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:
--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— один и тот же паттерн. - Пустое значение не совпадает ни с чем, включая глобальное пространство имён.
Фильтрует нарушения и худших нарушителей по выбранным пространствам имён. Показывает оценки здоровья поддерева. Автоматически включает --detail.
Находки уровня проекта (architecture.coverage-gap и прочие диагностики, судящие о прогоне целиком) не выбираются паттерном пространства имён никогда, включая *: они не принадлежат ни одному пространству имён.
То же правило сопоставления действует для drill-down по здоровью и списков худших нарушителей, которые включает эта опция, и для опции include_namespaces правила coupling.distance.
Паттерн, не выбравший ни одного проанализированного пространства имён, отвергается с кодом 3, и отказ называет, сколько пространств имён у прогона было. Паттерн, который что-то выбрал и всё равно ничего не сообщил, печатает обычный пустой результат — именно эти два исхода и важно различать.
Взаимоисключающий с --class.
--class¶
Фильтрация вывода по конкретному классу с точным совпадением FQCN.
Фильтрует нарушения по указанному классу. Автоматически включает --detail.
FQCN, не совпавший ни с одним проанализированным классом, отвергается с кодом 3
по той же причине, что и --namespace: иначе пустой отчёт читается как чистый
класс.
Взаимоисключающий с --namespace.
Опции кэширования¶
Qualimetrix кэширует разобранные AST-деревья для ускорения повторных запусков.
--no-cache¶
Полностью отключить кэширование:
--cache-dir¶
Указать директорию кэша. По умолчанию: .qmx-cache.
Директория создаётся, если её нет. Путь, который не удаётся создать или в
который нельзя писать, отвергается с кодом 3, а не выключает кэш молча; дверь
закрывается так же во всех командах, разрешающих директорию кэша, а не только в
check.
--clear-cache¶
Очистить кэш перед запуском анализа:
Опции baseline¶
Полный жизненный цикл и формат файла описаны в Baseline.
--baseline=BASELINE¶
Использовать файл baseline, чтобы применить принятые потолки к текущим нарушениям:
--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 (см.
«Правила»):
Независимо от --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:
Опция не меняет то, что измеряет baseline
Флаг влияет только на отчёт. Baseline измеряет те нарушения, которые
оставляют конфигурация и аннотации в исходниках, поэтому нарушение,
убранное тегом @qmx-ignore, никогда не попадает в baseline и никогда не
сравнивается с ним — независимо от того, передан ли этот флаг.
Видимое следствие: под этим флагом подавленное аннотацией нарушение
показывается со своей собственной серьёзностью и никогда не повышается
до ошибки, потому что ни одна запись baseline его не покрывает. Флаг может
сузить измеряемое baseline множество (--suppress-path,
--suppress-namespace), но расширить его не может ни один.
Опции области Git¶
Вывод нарушений только для изменённых файлов. Полное руководство смотрите в разделе Интеграция с Git.
--report¶
Управление тем, какие нарушения выводить. Анализирует весь проект, но показывает только нарушения из изменённых файлов:
--report-strict¶
В режиме diff показывать нарушения только из самих изменённых файлов. Без этого флага также выводятся нарушения из родительских пространств имён:
Опции выполнения¶
--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¶
Записывать отладочный лог в файл:
--log-level¶
Установить минимальный уровень логирования. По умолчанию: info.
Доступные уровни: debug, info, warning, error. Значение вне этого набора
отвергается с кодом 3, а не откатывается к info.
--no-progress¶
Отключить прогресс-бар. Полезно в CI-пайплайнах:
Принимается каждой командой, которая показывает прогресс-бар: 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, подавляющие обычный вывод. Оба принимаются любой командой:
--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.
Доступные форматы: 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-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
}
assigned—null, если ни один слой не совпал (в этом случае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:
hook:status¶
Показать текущий статус хука pre-commit:
hook:uninstall¶
Удалить хук pre-commit:
bin/qmx hook:uninstall
# Восстановить оригинальный хук из резервной копии
bin/qmx hook:uninstall --restore-backup
rules¶
Вывести список всех доступных правил с описаниями и опциями CLI:
Пример вывода (для --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, в которую он разворачивается. Значений порогов по
умолчанию в этом выводе нет — они описаны в
Пороговых значениях по умолчанию.