diffyml: структурный YAML diff с поддержкой Kubernetes

diffyml output

Быстрый структурный инструмент сравнения YAML (YAML diff) со встроенной поддержкой Kubernetes. Одна зависимость, минимальная поверхность атаки, нативные аннотации CI для GitHub, GitLab и Gitea.

📖 Полная документация: szhekpisov.github.io/diffyml

diffyml сравнивает YAML-файлы и показывает осмысленные, структурированные различия — а не построчные текстовые диффы.

Почему diffyml?

Самый быстрый структурный инструмент YAML-диффа при работе с большими файлами. На больших (5K строк) и очень больших (50K строк) входных данных diffyml в 1,5–1,9× быстрее ближайшего YAML-осведомлённого конкурента. На небольших и средних файлах результаты сопоставимы с разницей в несколько миллисекунд — остаточные накладные расходы объясняются возможностями, которых более простым инструментам не хватает (инспекция сертификатов x509, загрузка удалённых URL, AI-сводки). Методология и результаты описаны в PERFORMANCE.md.

Одна зависимость, никаких сюрпризов. Единственная зависимость модуля — yaml.v3 и чистая стандартная библиотека Go. Минимальная поверхность атаки, поддаётся аудиту за считанные минуты.

Правильная обработка YAML. Точечные ключи (dotted keys), сохранение типов (type preservation), списки смешанных типов (mixed-type lists), nil-значения — конкретные граничные случаи, с которыми другие инструменты справляются неверно. diffyml относится к семантике YAML как к объекту первого класса, а не как к чему-то второстепенному.

Сравнение с аналогами

Возможность diffyml dyff обычный diff

YAML-осведомлённость (структурный diff)

Да

Да

Нет (построчный)

Сопоставление ресурсов Kubernetes

По apiVersion + kind + name (или generateName)

По apiVersion + kind + name

Нет

Обнаружение переименований (rename detection)

Да (схожесть содержимого — обрабатывает смену имён)

Да (по идентификатору — имя должно оставаться неизменным)

Нет

Миграция версий API

Да (--ignore-api-version)

Нет

Нет

Форматы аннотаций CI

3 (GitHub, GitLab, Gitea)

0

0

Зависимости модуля

1 (yaml.v3)

23

0

Сравнение директорий

Да

Нет

Да

Внешний diff для Git (GIT_EXTERNAL_DIFF)

Да (авто-определение)

Вручную (скрипт-обёртка)

Н/П

Встроенная подсветка различий (inline diff highlighting)

Да (на уровне слов)

Да (на уровне символов)

Нет

Настраиваемые цвета

Да (hex, переменные окружения)

Нет

Нет

Файл конфигурации

Да (.diffyml.yml)

Нет

Нет

Производительность (78 КБ)

19 мс

120 мс (6.4×)

6 мс

Производительность (780 КБ)

129 мс

1 146 мс (8.9×)

45 мс

Сравнение основано на dyff v1.11.3 и diffyml v1.5.23. Полная методология бенчмарков и результаты сравнения с 5 конкурентами — в PERFORMANCE.md. Откройте issue, если что-то устарело.

Установка

Homebrew

brew tap szhekpisov/diffyml
brew install diffyml

Go Install

go install github.com/szhekpisov/diffyml@latest

Убедитесь, что $GOPATH/bin присутствует в переменной PATH:

export PATH="$(go env GOPATH)/bin:$PATH"

Скрипт установки (Linux / macOS)

curl -fsSL https://szhekpisov.github.io/diffyml/install.sh | sh

Скрипт определяет ОС и архитектуру, загружает соответствующий архив релиза, проверяет его SHA256 по подписанному checksums.txt и устанавливает файл в /usr/local/bin/diffyml. Настраивается через переменные окружения:

Переменная По умолчанию Примечания

DIFFYML_VERSION

последний релиз

Зафиксировать конкретную версию, например 1.6.1. Рекомендуется в CI — позволяет избежать неаутентифицированного вызова GitHub API (60 запросов/час на IP), используемого для определения последнего тега.

INSTALL_DIR

/usr/local/bin

Если директория недоступна для записи, используется sudo.

VERIFY

sha256

Укажите cosign, чтобы сначала проверить cosign-подпись checksums.txt (требуется cosign в PATH), или none, чтобы пропустить проверку.

GITHUB_TOKEN

не задан

Если задан, используется для аутентификации при вызове GitHub API для определения последней версии. Полезно на общих IP-адресах CI.

# Зафиксировать версию, установить в ~/bin, также проверить cosign-подпись:
DIFFYML_VERSION=1.6.1 INSTALL_DIR="$HOME/bin" VERIFY=cosign \
  sh -c "$(curl -fsSL https://szhekpisov.github.io/diffyml/install.sh)"

Пакеты Linux (.deb / .rpm / .apk)

Нативные пакеты для Debian/Ubuntu, RHEL/Fedora и Alpine (amd64 и arm64) прикреплены к каждому релизу. Все архивы пакетов перечислены в подписанном cosign файле checksums.txt, поэтому вы можете проверить их до установки — см. раздел Проверка релизов. Файл .apk использует флаг --allow-untrusted, поскольку пакеты, собранные nfpm, не подписаны GPG; вместо этого следует проверять SHA256 из checksums.txt.

# Debian / Ubuntu
curl -fLO "https://github.com/szhekpisov/diffyml/releases/download/v1.6.1/diffyml_1.6.1_linux_amd64.deb"
sudo dpkg -i diffyml_1.6.1_linux_amd64.deb

# RHEL / Fedora / openSUSE
curl -fLO "https://github.com/szhekpisov/diffyml/releases/download/v1.6.1/diffyml_1.6.1_linux_amd64.rpm"
sudo rpm -i diffyml_1.6.1_linux_amd64.rpm

# Alpine
curl -fLO "https://github.com/szhekpisov/diffyml/releases/download/v1.6.1/diffyml_1.6.1_linux_amd64.apk"
sudo apk add --allow-untrusted diffyml_1.6.1_linux_amd64.apk

Бинарный файл устанавливается в /usr/bin/diffyml.

Прямая загрузка бинарного файла

Если вы предпочитаете не передавать скрипт в sh, те же архивы прикреплены к каждому релизу для Linux и macOS (amd64 и arm64):

VERSION=1.6.1  # проверьте страницу релизов для последней версии
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/')
curl -fL "https://github.com/szhekpisov/diffyml/releases/download/v${VERSION}/diffyml_${VERSION}_${OS}_${ARCH}.tar.gz" \
  | tar -xz
sudo mv diffyml /usr/local/bin/

Перед установкой ознакомьтесь с разделом Проверка релизов, чтобы убедиться в подлинности подписей и происхождения.

Docker

Мультиархитектурные образы (linux/amd64, linux/arm64) публикуются в GitHub Container Registry:

docker pull ghcr.io/szhekpisov/diffyml:latest

# Сравнить два файла из текущей директории
docker run --rm -v "$PWD:/work" -w /work ghcr.io/szhekpisov/diffyml:latest old.yaml new.yaml

Образы собраны на базе distroless и запускаются от имени непривилегированного пользователя. Используйте :latest или зафиксируйте конкретную версию (например, :1.5.25).

Сборка из исходного кода

git clone https://github.com/szhekpisov/diffyml.git
cd diffyml
go build -o diffyml

Проверка релизов

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

  • Контрольные суммы (checksums.txt) — хэши SHA256 для всех архивов

  • Подпись cosign (checksums.txt.sigstore.json) — беспарольная (keyless) подпись Sigstore

  • SBOM (*.spdx.json) — SPDX Software Bill of Materials (перечень компонентов программного обеспечения) для каждого архива

  • Происхождение SLSA — аттестация сборки уровня Level 3

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

cosign verify-blob checksums.txt \
  --bundle checksums.txt.sigstore.json \
  --certificate-identity-regexp 'https://github.com/szhekpisov/diffyml/' \
  --certificate-oidc-issuer 'https://token.actions.githubusercontent.com'

# Linux
sha256sum --check checksums.txt --ignore-missing
# macOS
shasum -a 256 --check checksums.txt --ignore-missing

Проверка происхождения SLSA:

gh attestation verify diffyml_<VERSION>_linux_amd64.tar.gz \
  --repo szhekpisov/diffyml

Проверка подписи образа контейнера:

cosign verify \
  --registry-referrers-mode=oci-1-1 \
  --certificate-identity-regexp 'https://github.com/szhekpisov/diffyml/' \
  --certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
  ghcr.io/szhekpisov/diffyml:<VERSION>

Быстрый старт

# Сравнить два локальных файла
diffyml old.yaml new.yaml

# Сравнить локальный файл с удалённым URL
diffyml local.yaml https://example.com/remote.yaml

# Использование в CI — код выхода 1 при обнаружении различий
diffyml -s deployment-old.yaml deployment-new.yaml

# Использование в качестве внешнего провайдера diff для kubectl:
export KUBECTL_EXTERNAL_DIFF="diffyml --omit-header --set-exit-code"
kubectl diff with diffyml

Возможности

  • 7 форматов вывода — detailed (подробный), compact (компактный), brief (краткий), GitHub, GitLab, Gitea, JSON

  • Фильтрация по путям — включение/исключение путей по точному совпадению или регулярному выражению

  • Удалённые файлы — сравнение напрямую по HTTP/HTTPS URL

  • Инспекция сертификатов — проверка и сравнение встроенных сертификатов x509

  • Chroot-навигация — фокусировка сравнения на конкретном поддереве YAML

  • Интеграция с Git — использование в качестве GIT_EXTERNAL_DIFF или через .gitattributes для области действия только на YAML

  • Встроенная подсветка различий — выделяет только изменённые части скалярных значений (теги версий, IP-адреса, порты) для быстрого просмотра

  • Настраиваемые цвета — настраиваемая цветовая палитра для обеспечения доступности (удобно для людей с цветовой слепотой)

  • Файл конфигурации — настройки уровня проекта через .diffyml.yml (поддерживаются все флаги)

  • Маскирование чувствительных значений — опциональное скрытие полей data / stringData секретов Kubernetes и произвольных путей; применяется ко всем форматам вывода

  • AI-сводки ⭐ — описание изменений на естественном языке через Anthropic API

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

diffyml [flags] <from> <to>

Форматы вывода

Формат Флаг Случай использования

detailed (подробный)

-o detailed (по умолчанию)

Ручная проверка — полный контекст

compact (компактный)

-o compact

Быстрый просмотр изменений

brief (краткий)

-o brief

Только сводка

github

-o github

Аннотации GitHub Actions

gitlab

-o gitlab

Аннотации GitLab CI

gitea

-o gitea

Аннотации Gitea CI

json

-o json

Машиночитаемый — для передачи по конвейеру, скриптов, CI

Интеграция с CI

Используйте -s / --set-exit-code, чтобы устанавливать код выхода на основе наличия различий:

Код выхода Значение

0

Различий нет (или успех без -s)

1

Обнаружены различия (только с -s)

255

Произошла ошибка

diffyml -s before.yaml after.yaml || echo "Config drift detected"

GitHub Actions — используйте составное действие diffyml-action (без ручной установки бинарного файла):

- uses: szhekpisov/diffyml-action@v1
  with:
    from: old.yaml
    to: new.yaml

Чтобы проверить расхождения без провала задания, считайте вывод has-differences:

- uses: szhekpisov/diffyml-action@v1
  id: diff
  with:
    from: old.yaml
    to: new.yaml
    fail-on-diff: 'false'
    output: github

- if: steps.diff.outputs.has-differences == 'true'
  run: echo "Configuration drift detected"

Полный список входных и выходных параметров см. в репозитории действия.

Поддержка Kubernetes

Ресурсы определяются автоматически и сопоставляются по apiVersion + kind + metadata.name (или metadata.generateName), поэтому диффы остаются осмысленными даже при изменении порядка документов.

Обнаружение переименований — когда ресурсы не могут быть сопоставлены по идентификатору (например, при изменении хэш-суффиксов configMapGenerator в kustomize, таких как app-config-abc123app-config-def456), diffyml сопоставляет несовпавшие документы по схожести содержимого (порог 60%) и отображает диффы на уровне полей вместо массового добавления/удаления. Отключается флагом --detect-renames=false.

Миграция API — флаг --ignore-api-version исключает apiVersion из ключа сопоставления, поэтому при обновлении с apps/v1beta1 до apps/v1 отображаются диффы на уровне полей вместо удаления + добавления.

Отключение--detect-kubernetes=false полностью отключает K8s-осведомлённое сопоставление и сравнивает документы по позиции.

# Сравнить два манифеста Kubernetes
diffyml manifests-v1.yaml manifests-v2.yaml

# Миграция API — сопоставление только по kind + name
diffyml --ignore-api-version manifests-v1.yaml manifests-v2.yaml

# Отключить определение Kubernetes
diffyml --detect-kubernetes=false file1.yaml file2.yaml

Сравнение директорий

diffyml принимает две директории в качестве позиционных аргументов. Он рекурсивно обнаруживает все обычные файлы в каждой директории (независимо от расширения), сопоставляет их по относительному пути и отображает агрегированные различия. Файлы, которые не удаётся разобрать как YAML, молча пропускаются.

Это делает diffyml полноценным провайдером KUBECTL_EXTERNAL_DIFF — kubectl передаёт две временные директории, содержащие временные файлы без расширения (например, apps.v1.Deployment.default.nginx), и diffyml обнаруживает их автоматически:

export KUBECTL_EXTERNAL_DIFF="diffyml --omit-header --set-exit-code"
kubectl diff -f manifests/

Интеграция с Git

diffyml может использоваться как внешняя программа diff для git. Git передаёт 7–9 позиционных аргументов, которые diffyml определяет автоматически — не-YAML файлы пропускаются с предупреждением.

# Разовое использование: структурный diff для изменений YAML в рабочем дереве
GIT_EXTERNAL_DIFF=diffyml git diff

# С флагами (например, компактный вывод)
GIT_EXTERNAL_DIFF='diffyml -o compact' git diff

Для постоянной настройки используйте .gitattributes — встроенный diff git нормально обрабатывает все остальные типы файлов:

*.yaml diff=diffyml
*.yml  diff=diffyml
git config diff.diffyml.command diffyml

Цвет и truecolor (24-битный цвет) включаются автоматически (пейджер git делает stdout каналом). Используйте --color never для отключения. Флаг --set-exit-code молча игнорируется — git прерывает работу внешних программ diff, которые завершаются с ненулевым кодом. Ошибки разбора не являются фатальными: выводится предупреждение, и git переходит к следующему файлу.

AI-сводка

Генерация описания изменений на естественном языке с использованием Anthropic API:

export ANTHROPIC_API_KEY="sk-ant-..."

# Добавить AI-сводку после вывода diff
diffyml --summary old.yaml new.yaml

# Использовать с форматом brief — заменяет краткий вывод AI-сводкой
diffyml --summary -o brief old.yaml new.yaml

# Использовать другую модель
diffyml --summary --summary-model claude-sonnet-4-5-20250514 old.yaml new.yaml

Сводка добавляется после стандартного вывода diff. Если вызов API завершается с ошибкой, предупреждение выводится в stderr, а вывод diff сохраняется. Код выхода никогда не зависит от успеха или неудачи сводки.

Маскирование чувствительных значений

Маскирование является опциональным. При включении diffyml заменяет значение любого совпадающего диффа на * перед отображением — применяется ко всем форматам вывода (включая json, json-patch и промпт --summary). Диффы по-прежнему показывают факт изменения значения, но не само значение.

# Автоматически маскировать data/stringData ресурсов Kubernetes Secret
diffyml --mask-secrets secrets-old.yaml secrets-new.yaml

# Маскировать дополнительные пути (например, поле ConfigMap, содержащее API-ключ)
diffyml --mask-path 'data.api_key' --mask-path 'data.db_url' old.yaml new.yaml

# Вариант с регулярным выражением — маскировать любое поле, чей путь совпадает
diffyml --mask-path-regexp '(?i)password|token|secret' old.yaml new.yaml

# Пользовательская метка-заглушка
diffyml --mask-secrets --mask-placeholder '<REDACTED>' old.yaml new.yaml

Пути маскирования используют ту же точечную нотацию, что и --filter / --exclude (с учётом совпадения по префиксу). Ведущий индекс документа для многодокументных файлов ([0], [1]) автоматически удаляется перед сопоставлением.

Настройте значения по умолчанию в .diffyml.yml, чтобы маскирование было всегда включено для данного репозитория:

mask-secrets: true
mask-path:
  - "data.api_key"
mask-path-regexp:
  - "(?i)password"
mask-placeholder: "***"

Фильтрация

# Показывать только изменения по определённому пути
diffyml --filter spec.replicas old.yaml new.yaml

# Исключить «шумные» пути
diffyml --exclude metadata.annotations old.yaml new.yaml

# Ключи с точками используют синтаксис в скобках
diffyml --exclude 'metadata.annotations[argocd.argoproj.io/tracking-id]' old.yaml new.yaml

# Фильтрация с регулярными выражениями
diffyml --filter-regexp 'spec\.containers\[.*\]\.image' old.yaml new.yaml

Аккуратный режим (Neat Mode)

Флаг --neat исключает широко известные «шумные» пути, добавляемые сервером Kubernetes API, kubectl, Helm, ArgoCD и Flux — metadata.managedFields, metadata.resourceVersion, всё поддерево status, meta.helm.sh/release-name, helm.sh/chart, argocd.argoproj.io/tracking-id, kustomize.toolkit.fluxcd.io/* и аналогичные пути. Полный список исключаемых путей находится в doc/neat.md.

# Сравнить манифест, отрендеренный kube-apiserver, с вашим эталонным источником
# (с использованием подстановки процессов; diffyml читает файлы, не stdin)
diffyml --neat <(kubectl get deployment nginx -o yaml) source.yaml

# В рабочем процессе kubectl/helm/argocd diff
KUBECTL_EXTERNAL_DIFF="diffyml --neat" kubectl diff -f deployment.yaml

# Посмотреть, что именно отфильтровал --neat
diffyml --neat --neat-explain old.yaml new.yaml

Опции отказа от отдельных слоёв позволяют сохранить один набор исключений, убрав остальные:

# Показывать диффы версий Helm-чартов, но всё равно убирать ArgoCD/Flux/managedFields
diffyml --neat --no-neat-helm old.yaml new.yaml

--neat-strip-path расширяет набор без пересборки (требует --neat):

diffyml --neat --neat-strip-path '^metadata\.annotations\[my\.org/.*\]$' old.yaml new.yaml

--neat намеренно сохраняет spec.template.metadata.annotations[kubectl.kubernetes.io/restartedAt] (маркер намеренного перезапуска), spec.replicas, data/stringData (для них используйте --mask-secrets) и пользовательские метки/аннотации за пределами канонических шумовых префиксов.

Файл конфигурации

diffyml загружает настройки уровня проекта из .diffyml.yml (или .diffyml.yaml) в текущей директории. Флаги командной строки переопределяют значения из файла конфигурации. Используйте --config для указания пути к пользовательскому файлу конфигурации.

# .diffyml.yml
output: compact
ignore-order-changes: true
detect-kubernetes: false
filter:
  - "spec.containers"
exclude:
  - "status"

Все флаги командной строки поддерживаются в качестве ключей конфигурации (в формате kebab-case, совпадающем с длинным именем флага). Неизвестные ключи отклоняются для выявления опечаток. Полный справочник со всеми ключами и значениями по умолчанию см. в .diffyml.yml.example.

Настраиваемые цвета

Цвета diff можно настроить для обеспечения доступности (например, палитры для людей с цветовой слепотой). Доступны для настройки пять цветовых ролей: added (добавлено), removed (удалено), modified (изменено), context (контекст) и doc-name (имя документа).

Цвета задаются в формате hex (#rrggbb, #rgb).

Через файл конфигурации:

# .diffyml.yml
colors:
  added: "#6aa3a5"
  removed: "#702d06"

Через переменные окружения (переопределяют файл конфигурации):

export DIFFYML_COLOR_ADDED="#6aa3a5"
export DIFFYML_COLOR_REMOVED="#702d06"
diffyml old.yaml new.yaml

Доступные переменные окружения: DIFFYML_COLOR_ADDED, DIFFYML_COLOR_REMOVED, DIFFYML_COLOR_MODIFIED, DIFFYML_COLOR_CONTEXT, DIFFYML_COLOR_DOC_NAME.

Все флаги

Вывод

Флаг Описание

-o, --output <style>

Стиль вывода: detailed, compact, brief, github, gitlab, gitea, json (по умолчанию detailed)

-c, --color <mode>

Использование цвета: always, never, auto (по умолчанию auto)

-t, --truecolor <mode>

True color (24-бит): always, never, auto (по умолчанию auto)

Сравнение

Флаг Описание

-i, --ignore-order-changes

Игнорировать изменения порядка в списках

--ignore-whitespace-changes

Игнорировать различия в начальных/конечных пробелах

--format-strings

Канонизировать встроенные JSON-строки перед сравнением (подавляет диффы, связанные только с форматированием)

-v, --ignore-value-changes

Показывать только структурные изменения, исключать изменения значений

--detect-kubernetes

Определять и сопоставлять ресурсы Kubernetes (по умолчанию true)

--detect-renames

Обнаруживать переименованные/перемещённые ресурсы Kubernetes по схожести содержимого (по умолчанию true)

--ignore-api-version

Игнорировать apiVersion при сопоставлении ресурсов Kubernetes

-x, --no-cert-inspection

Отключить инспекцию сертификатов x509

--swap

Поменять местами файлы from/to

Фильтрация

Флаг Описание

--filter <path>

Включать только различия по указанным путям (повторяемый)

--exclude <path>

Исключать различия по указанным путям (повторяемый)

--filter-regexp <pattern>

Фильтровать с использованием регулярных выражений (повторяемый)

--exclude-regexp <pattern>

Исключать с использованием регулярных выражений (повторяемый)

--additional-identifier <field>

Дополнительное поле для идентификации элементов списка

Маскирование чувствительных значений

Флаг Описание

--mask-secrets

Автоматически маскировать data / stringData ресурсов Kubernetes Secret

--mask-path <path>

Дополнительный путь для маскирования, точечная нотация с совпадением по префиксу (повторяемый)

--mask-path-regexp <pattern>

Дополнительный путь для маскирования, регулярное выражение (повторяемый)

--mask-placeholder <string>

Метка-заглушка для маскированных значений (по умолчанию *)

Отображение

Флаг Описание

-b, --omit-header

Не выводить заголовок сводки

-g, --use-go-patch-style

Использовать пути в стиле Go-Patch

--multi-line-context-lines <int>

Строки контекста для многострочных строк (по умолчанию 4)

Chroot

Флаг Описание

--chroot <path>

Изменить корневой уровень для обоих файлов

--chroot-of-from <path>

Изменить корневой уровень только для файла from

--chroot-of-to <path>

Изменить корневой уровень только для файла to

--chroot-list-to-documents

Рассматривать список chroot как отдельные документы

AI-сводка

Флаг Описание

-S, --summary

Генерировать AI-сводку на естественном языке (требует ANTHROPIC_API_KEY)

--summary-model <model>

Модель для AI-сводки (по умолчанию claude-haiku-4-5-20251001)

Прочее

Флаг Описание

--config <path>

Путь к файлу конфигурации (по умолчанию .diffyml.yml в текущей директории)

-s, --set-exit-code

Код выхода 1, если обнаружены различия

-h, --help

Показать справку

-V, --version

Показать информацию о версии

Использование в качестве библиотеки

diffyml можно использовать как библиотеку Go для программного сравнения YAML.

import "github.com/szhekpisov/diffyml/pkg/diffyml"

// Сравнить два YAML-документа
from, _ := diffyml.LoadContent("old.yaml")
to, _   := diffyml.LoadContent("new.yaml")

diffs, err := diffyml.Compare(from, to, &diffyml.Options{
    DetectKubernetes: true,
})
if err != nil {
    log.Fatal(err)
}

// Отформатировать различия
formatter, _ := diffyml.FormatterByName("compact")
fmt.Print(formatter.Format(diffs, diffyml.DefaultFormatOptions()))

Полный справочник API см. в документации пакета.

Безопасность и качество кода

Цепочка поставок (supply chain). Релизы подписаны с помощью cosign (беспарольный Sigstore), содержат SPDX SBOM для каждого артефакта и несут SLSA Level 3 — аттестацию происхождения сборки. Опубликованные теги неизменяемы. Команды верификации см. в разделе Проверка релизов. Репозиторий отслеживается OpenSSF Scorecard (значок выше).

Непрерывные проверки. Каждый push и PR проверяются:

  • govulncheck — обнаружение известных уязвимостей (также запускается на main еженедельно)

  • zizmor — сканирование безопасности рабочих процессов GitHub Actions

  • golangci-lint с запуском: errcheck, gocritic, gosec, govet (с обнаружением затенения переменных), ineffassign, misspell, staticcheck (все проверки, кроме стилистических соглашений)

Качество тестов. 1 500+ тестов (модульные, e2e, фаззинг, основанные на свойствах), покрытие кода 99,4%, мутационное тестирование контролируется при каждом PR (ни один выживший мутант на изменённых строках) с минимальным порогом эффективности после слияния 85,65%. CI обеспечивает минимальный порог покрытия 99%.

Сообщение об уязвимостях. См. SECURITY.md — предпочтительный путь — частное уведомление безопасности GitHub.

Вклад в проект

Вклад приветствуется! Откройте issue для сообщения об ошибках или запросов функций.

Предварительные требования: Go 1.26.3+, pre-commit

git clone https://github.com/szhekpisov/diffyml.git
cd diffyml
pre-commit install

Pre-commit хуки запускаются автоматически при каждом коммите:

Хук Что проверяет

gofmt

Форматирование кода

go vet

Статический анализ

check-coverage

Порог покрытия (99% в целом)

govulncheck

Известные уязвимости

golangci-lint

7 линтеров (errcheck, gocritic, gosec, govet, ineffassign, misspell, staticcheck)

Полезные цели Make:

make test           # запустить все тесты
make ci             # полный CI-конвейер локально (fmt + vet + test + coverage + security)
make bench          # запустить бенчмарки
make bench-compare  # сравнить с альтернативными инструментами (см. doc/PERFORMANCE.md)
make coverage       # сгенерировать HTML-отчёт о покрытии
make mutation       # запустить мутационное тестирование (требует gomutants)

CI-конвейеры (запускаются при каждом push и PR):

  • Tests — модульные тесты + пороги покрытия

  • Security & Static Analysis — govulncheck + golangci-lint (также запускается еженедельно)

  • Benchmark — отслеживание регрессий производительности

  • Mutation Testing — валидация качества тестов через gomutants

Благодарности

Этот проект во многом вдохновлён dyff, и он не был бы возможен без огромной работы мейнтейнеров и контрибьюторов этого проекта.

Лицензия

MIT.


Если этот проект оказался вам полезен, пожалуйста, поставьте ⭐ — это помогает другим его найти.

© 2026 meganuke