Фиксация версий плагинов и тем для старых установок Discourse (ветки d-compat)

:open_book: Контекст

Разработчики тем и плагинов, как правило, хотят ориентироваться на latest-релиз Discourse, не беспокоясь о обратной совместимости. Однако сайтам, работающим на более старых версиях Discourse, по-прежнему нужна версия темы/плагина, которая будет для них работать.

Чтобы преодолеть этот разрыв, Discourse можно указать, чтобы он проверял более старую «закреплённую» (pinned) версию темы/плагина. Для этого существуют два механизма, которые проверяются в следующем порядке:

  1. Git-ветки d-compat/<YYYY>.<M> в репозитории темы/плагина (основной метод — рекомендуется для всех новых закреплений).
  2. YAML-файл .discourse-compatibility в корне репозитория (изначальный механизм, по-прежнему поддерживается как запасной вариант).

Если оба варианта существуют, приоритет отдаётся ветке.

:herb: Система веток d-compat/<YYYY>.<M>

Релизы Discourse используют версии на основе даты, такие как 2025.5, 2025.6 и т. д. Когда Discourse обновляет плагин или тему из git, он обращается к репозиторию с вопросом: «Есть ли у вас ветка с именем d-compat/<YYYY>.<M>, соответствующая моей версии?» (например, d-compat/2025.5 для Discourse 2025.5.x). Если такая ветка есть, Discourse выполняет checkout её последней коммиты, а не ветки main.

Поиск выполняется только в том случае, если локальный checkout находится на ветке по умолчанию репозитория. Если вы намеренно закрепили другую ветку, логика d-compat пропускается, и ваше закрепление учитывается.

Чтобы поддержать более старую версию Discourse с помощью этой системы:

  1. Создайте ветку с именем d-compat/<YYYY>.<M> из коммита, который, как известно, работает с этой версией (например, git checkout -b d-compat/2025.5 <commit>).
  2. Отправьте её на origin. Возможно, вы захотите защитить ветку от случайного удаления.
  3. Внесите любые коммиты для обратной портировки (backport) в эту ветку. Экземпляры Discourse на 2025.5.x автоматически подхватят их при следующем обновлении; экземпляры на более новых версиях Discourse продолжат отслеживать ветку по умолчанию.

При использовании веток вам вообще не нужно трогать .discourse-compatibility.

:gear: Автоматическое создание веток (create-d-compat-branch.yml)

На практике вам редко приходится создавать эти ветки вручную. В стандартных шаблонах тем и плагинов есть workflow d-compat-branch.yml, который запускается ежедневно, проверяет наличие новых версий ядра Discourse и при необходимости отправляет соответствующие ветки d-compat/<YYYY>.<M>.

Если ваш репозиторий был создан из более старой копии шаблонов, просто скопируйте файл d-compat-branch.yml в ваш каталог .github/workflows, чтобы запустить его работу.

:git_merged: Обратная портировка исправления в ветку d-compat

Когда вы внесли исправление в ветку по умолчанию, которое также должно быть доступно сайтам на более старых релизах Discourse:

  1. Создайте ветку от целевой ветки d-compat и выполните cherry-pick исправления:

    git fetch origin
    git checkout -b backport/my-fix-2025.5 origin/d-compat/2025.5
    git cherry-pick <commit-sha>
    git push -u origin backport/my-fix-2025.5
    
  2. Откройте PR, указав d-compat/2025.5 как базовую ветку (а не main). Получите ревью и объедините его так же, как любой другой PR.

  3. Повторите для каждой более старой ветки d-compat/<YYYY>.<M>, которой требуется это исправление.

Сайты на 2025.5.x подхватят объединённый коммит при следующем обновлении.

Устаревший запасной вариант: файл `.discourse-compatibility`

Если соответствующая ветка d-compat не существует, Discourse обращается к YAML-файлу .discourse-compatibility в корне репозитория, который сопоставляет версии Discourse с git-ссылками (refs) вашего плагина/темы:

< 3.2.0.beta2-dev: abcde

Discourse выбирает самую нижнюю запись, соответствующую текущей версии ядра, поэтому все, кто находится на версии < 3.2.0.beta2-dev, выполняют checkout коммита abcde. Используйте < (или устаревший <=, который является значением по умолчанию, если оператор не указан), чтобы указать границу версии. Обращайтесь к этому механизму только в том случае, если система на основе веток не позволяет выразить то, что вам нужно.


Этот документ находится под контролем версий — предложите изменения на github.

17 лайков

Если версия < 3.5.0.beta8-dev, будет ли она включать 3.5.0?

Версия 3.5.0 считается «более высокой», чем версия предварительного выпуска «3.5.0.beta8-dev».

Вы всегда можете проверить сравнения в консоли Ruby:

> Gem::Version.new("3.5.0") < Gem::Version.new("3.5.0.beta8-dev")
=> false
5 лайков

Понял. Спасибо за объяснение!

1 лайк

Этот документ обновлён для описания новой стратегии d-compat/* из RFC: A new versioning strategy for Discourse, которая теперь доступна для использования.

5 лайков

Стратегия d-compat/<YYYY>.<M> потребовала бы создания отдельной ветки для каждого конкретного релиза, верно? Невозможно задать диапазон, как в конструкции .discourse-compatibility.

Допустим, я поддерживаю плагин, который работает от ESR до последней версии. Когда я переношу разработки на новый ESR (который перекрывается со старым ESR), мне нужно создавать ветки для каждой промежуточной версии?

Например, сейчас ESR — 2026.1, текущий релиз — 2026.6, а последняя версия — 2026.7, которая всё ещё поддерживается в 2026.5. Когда я переношу свой плагин на новый ESR (2026.7), при этом старый ESR всё ещё поддерживается Discourse, мне нужно создать следующие ветки:

  • d-compat/2026.1
  • d-compat/2026.2
  • d-compat/2026.3
  • d-compat/2026.4
  • d-compat/2026.5
  • d-compat/2026.6

Где версии от .2 до .5 (включительно) уже не поддерживаются Discourse, но пользователи могут всё ещё ими пользоваться.

Или Discourse находит наиболее подходящую ветку, если нужная отсутствует, вместо того чтобы предполагать использование главной ветки?

Например, если я использую версию 2026.5, а существуют только ветки d-compat/2026.1 и d-compat/2026.6. Какая ветка будет использована?

  1. d-compat/2026.1, как ближайшая совместимая версия?
  2. main, поскольку нет конкретной ветки?
1 лайк

Да, для каждой версии ядра Discourse требуется отдельная ветка. Мы рекомендуем автоматизировать их создание:

Будет использована ветка main.

2 лайка