Инженерия

Форматы файлов changelog: JSON, YAML или просто Markdown

5 мин чтения

Большинство команд начинают changelog как файл Markdown, потому что это путь наименьшего сопротивления: читаемо в diff pull request’а, читаемо на GitHub без какого-либо рендеринга, и знакомо любому, кто когда-либо писал README. Этот выбор работает нормально ровно до того момента, когда файл нужно прочитать чему-то, кроме человека, странице, виджету, сводке по email, и тогда формат перестаёт быть бесплатным. Автоматизация changelog разбирает структурное требование в общем, тип, дата, тело и ссылка; это про то, какой формат файла реально доставляет эту структуру и сколько стоит до неё добраться с каждым.

Что не так с простым changelog в Markdown?

Ничего, пока что-то не должно распарсить его обратно в поля. Заголовок, дата и список под ним тривиально читать человеку и по-настоящему трудно надёжно распарсить, потому что у Markdown нет схемы: дата может быть в заголовке, жирным на первой строке, или вовсе отсутствовать в старой записи, и каждый из этих вариантов — валидный Markdown, который человек читает правильно, а парсер нет. Команды, автоматизирующие changelog в Markdown, обычно заканчивают тем, что пишут самодельный парсер на регулярках, который ломается в первый же раз, когда форматирование записи хоть немного отклоняется, что случается часто, потому что ничто не принуждает к согласованности при написании.

Что структурированный формат реально даёт?

Гарантию, что каждая запись имеет одну и ту же форму, проверенную при написании записи, а не угаданную при чтении. Файл JSON или YAML с определённой схемой, тип, дата, версия, аудитория, тело, ссылка, падает громко, если отсутствует обязательное поле, точно так же, как это сделал бы строгий ответ API; файл Markdown просто рендерит то, что там есть, правильно это или нет. Эта разница невидима до дня, когда скрипту нужна дата каждой записи, чтобы отсортировать поток, а у половины записей она в другом месте.

# CHANGELOG.yml
- date: 2026-09-05
  type: breaking
  version: v2
  audience: api
  body: "POST /invoices now rejects a currency mismatch instead of silently converting."
  link: /blog/api-changelog/

Значит ли это, что читаемый человеком файл должен исчезнуть?

Нет, и попытка заставить файл YAML или JSON служить одновременно тем, что человек читает в pull request, обычно ошибка в обратную сторону: ревью diff вложенного JSON хуже, чем ревью предложения прозы, а ревьюер, которому нужно мысленно распарсить структуру данных, чтобы поймать ошибку формулировки, — это ревьюер, который в конце концов перестанет ловить ошибки формулировки. Два формата могут сосуществовать: структурированные данные — источник истины, который читает пайплайн автоматизации, а сгенерированный рендер в Markdown или HTML — то, что человек реально ревьюит и читает, произведённое из структурированного файла вместо того, чтобы поддерживаться вручную рядом с ним.

ФорматЧитаем человеком как естьПарсится машиной без кастомного кодаЧастый режим отказа
MarkdownДаНетНепоследовательная форма записей ломает наивные парсеры
JSONПлохоДаМногословный; легко вручную отредактировать в невалидный JSON
YAMLТерпимоДаЧувствителен к пробелам; неверный отступ — тихая, не громкая ошибка парсинга

Какой структурированный формат реально легче редактировать вручную, JSON или YAML?

YAML, для тех, кто пишет записи вручную, а не через генератор, потому что он убирает кавычки и сопоставление скобок, которые JSON требует для каждой строки и вложенного объекта. Компромисс в том, что чувствительность YAML к пробелам ломается молча так, как обычно не ломаются несовпадения скобок в JSON: парсер JSON прямо отклоняет некорректный ввод, тогда как парсер YAML может принять файл с неверными отступами и просто распарсить его в неверную структуру, что худший отказ, потому что ничто не говорит вам, что это произошло. Если записи всегда пишет только скрипт, этот компромисс в основном исчезает, и более строгий парсинг JSON становится более безопасным выбором по умолчанию.

Нужен ли странице changelog собственный структурированный формат, отдельный от файла, который её питает?

Не отдельный, тот же самый, отрендеренный иначе. Страница changelog разбирает, как сделать саму страницу машиночитаемой через JSON-поток и разметку schema.org; этот поток — сгенерированный вывод, а не второй источник истины, который нужно держать синхронизированным с исходным файлом. Поддержка структурированных данных вручную в двух местах, исходном файле и потоке страницы, это то, как эти два расходятся, так что решение о формате файла, принятое здесь, должно быть единственным, из чего генерируется всё дальше по цепочке, страница, виджет, email, а не копироваться вручную.

Стоит ли затрат на миграцию переводить существующий changelog в Markdown в структурированный формат?

Обычно только когда автоматизация — реальная цель, не раньше. Проект одного человека, публикующий файл Markdown в README на GitHub, не имеет реальной потребности в автоматизации, и преобразование его в YAML не покупает ничего, кроме церемонии. Конверсия окупает себя в момент, когда больше одного потребителя дальше по цепочке, страница, письмо со сводкой, публичный поток, должны читать одни и те же данные, потому что это ровно та точка, где несогласованности парсера Markdown начинают производить заметно неправильный вывод вместо того, чтобы просто быть раздражающими в поддержке.

FAQ

Можно ли сделать changelog в Markdown парсимым без полной смены формата? Частично, с frontmatter: небольшой блок YAML в начале каждой записи (дата, тип, версия) рядом с телом на Markdown для прозы. Это даёт структурированные поля, которые нужны парсеру, не заставляя всю запись в JSON или YAML, и это разумная середина для команды, ещё не готовой к полной миграции.

Важен ли формат файла для SEO или для того, как ранжируется страница changelog? Не напрямую. Поисковики читают отрендеренную страницу, не исходный файл, так что формат файла для них невидим; важно для самой страницы то, машиночитаема ли она сама по себе, что отдельный вопрос от того, что её генерирует.

Должна ли каждая запись changelog проходить через один и тот же файл, или типы можно разделить по файлам? Один файл проще, пока объём записей не сделает его неудобным для diff’ов или ревью; разделение по году или категории — разумный клапан сброса давления, как только diff’ы одного файла становятся слишком большими, чтобы их разумно ревьюить, но это добавляет шаг слияния прежде, чем что-либо дальше по цепочке сможет прочитать «все записи» как один список.

Существует ли стандартный формат файла changelog, как существует стандарт для RSS? Не широко принятый. Keep a Changelog предлагает конвенцию Markdown, а несколько инструментов имеют собственный; changeset это файл Markdown с frontmatter на YAML, где названы пакет и тип повышения версии, то есть тот же паттерн с frontmatter, описанный выше. Ни один из них не формат, который другие инструменты читают из коробки так, как читатели RSS универсально понимают RSS.


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

По теме на changeloop: Сравнение инструментов changelog, Генератор changelog

changeloop
Команда, которая делает changelog, замыкающий цикл. Пользователи о чём-то просят, ваша команда это делает, тот, кто просил, узнаёт об этом.