RFC: Новая стратегия версионирования для Discourse

Мы планируем внедрить новую систему версионирования для Discourse. Наша цель — предоставить администраторам сообществ больше выбора и предсказуемости, сохраняя при этом темпы разработки. Мы также корректируем некоторые термины, чтобы лучше согласовать их с общепринятыми в других программных продуктах.

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

Если у вас есть комментарии или предложения на данном этапе, пожалуйста, сообщите нам, ответив на эту тему!


Цели

  1. Внедрить более регулярные «релизы» для Discourse, обеспечивающие баланс между скоростью разработки и стабильностью.

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

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

  4. Свести к минимуму церемонии вокруг «релизов». Максимально возможная часть процесса должна быть автоматизирована и не должна замедлять работу основных разработчиков. Релизы ESR ничем не отличаются от любых других релизов.

  5. Именование и процедуры должны соответствовать отраслевым стандартам, чтобы их было проще объяснять разработчикам и конечным пользователям.

Обзор высокого уровня

  • Выпускать примерно один релиз в месяц. «Мажорная» версия — это текущий год, а «минорная» версия увеличивается с каждым релизом. Номер версии патча будет увеличиваться для любых исправлений, перенесенных из других версий.

    Например, первый релиз 2026 года будет v2026.0, следующий — v2026.1 и так далее.

    Релизы будут получать критические исправления в течение двух полных циклов релизов. Например, поддержка 2026.0 будет продолжаться до выхода 2026.2.

  • Примерно каждые 6 месяцев один из этих релизов объявляется релизом с расширенной поддержкой (ESR). Версии ESR поддерживаются в течение 2 релизов после объявления следующего ESR.

    Например, если v2026.0 — это ESR, а v2026.6 — следующий ESR, то поддержка v2026.0 прекратится при выходе v2026.8. При ежемесячном цикле это означает 2 месяца пересечения поддержки ESR.

  • Предоставлять критические исправления для latest (самый последний релиз), предыдущего релиза и любых активных версий ESR.

  • Переименовать ветку tests-passed в latest.

Пример графика периодов поддержки в течение года:

gantt
    title Релизы и периоды поддержки Discourse (январь 2026 – январь 2027)
    dateFormat  YYYY-MM-DD
    axisFormat  %b %Y

    2026.0 (ESR) :active, 2026-01-27, 2026-09-29
    2026.1 :done, 2026-02-24, 2026-04-28
    2026.2 :done, 2026-03-31, 2026-05-26
    2026.3 :done, 2026-04-28, 2026-06-30
    2026.4 :done, 2026-05-26, 2026-07-28
    2026.5 :done, 2026-06-30, 2026-08-25
    2026.6 (ESR) :active, 2026-07-28, 2027-01-26
    2026.7 :done, 2026-08-25, 2026-10-27
    2026.8 :done, 2026-09-29, 2026-11-24
    2026.9 :done, 2026-10-27, 2026-12-29
    2026.10 :done, 2026-11-24, 2027-01-26
    2026.11 :done, 2026-12-29, 2027-01-26

Внедрение

  • Каждый релиз будет иметь ветку, созданную из latest. Они будут иметь пространство имен и сохраняться неограниченно долго. Например, для v2026.1 будет создана ветка с именем release/2026.1.

  • Каждый патч-релиз будет помечен тегом. Например: v2026.1.0, v2026.1.1 и т. д.

  • Последний релиз будет помечен тегом release. Последний ESR будет помечен тегом esr.

  • Предыдущий релиз будет помечен тегом release-previous. Предыдущая активная версия ESR (если есть) будет помечена тегом esr-previous.

  • Для обратной совместимости теги, соответствующие существующим потокам релизов, будут алиасами ближайших новых эквивалентов. stableesr. betarelease. tests-passedlatest.

    Эти теги будут считаться устаревшими, и мы планируем в будущем отказаться от некоторых или всех из них. В частности, «beta» проблематична, так как создает впечатление, что Discourse не готов к использованию в продакшене.

  • В ветке latest номер версии будет соответствовать текущей разрабатываемой версии с суффиксом -latest. Например: 2026.3.0-latest.

Автоматизированный процесс релизов

Каждый месяц действие GitHub открывает новый PR, содержащий один коммит, который обновляет version.rb в ветке main до следующей версии -latest.

После того как человек сольет PR, другое действие GitHub обнаружит переход main к следующей версии -latest и создаст ветку для завершенного релиза. По сути, эта ветка становится «кандидатом в релизы». Затем откроется еще один автоматический PR против ветки релиза с обновлением для удаления суффикса -latest из version.rb, тем самым «выпустив» релиз.

Обычно мы будем сливать эти два PR в quick succession. Но наличие отдельных PR для создания и завершения релиза дает нам возможность устранить любые проблемы в ветке перед финализацией.

    %%{init: { 'logLevel': 'debug', 'gitGraph': {'showBranches': true, 'showCommitLabel':true,'mainBranchOrder': 2}} }%%
    gitGraph
       checkout main
       commit id:'version v2026.1-latest'
       commit id:'...'
       commit id:'....'
       branch 'release/2026.1'
       commit id:'version 2026.1'
       checkout 'main'
       commit id:'version v2026.2-latest'

Отдельно другой рабочий процесс действий GitHub будет отслеживать любые коммиты с переносом исправлений в ветки релизов. При обнаружении таких коммитов будет создан новый PR для обновления номера патча в этой ветке. Человек может решить, когда сливать эти PR.

Все эти автоматизации будут автоматически поддерживать актуальность различных тегов (release, release-previous, esr, esr-previous, а также алиасы обратной совместимости).

Исправления безопасности

Рабочий процесс исправлений безопасности остается largely прежним, за исключением того, что теперь нам нужно вносить исправления в двух из этих трех новых мест:

  • latest

  • esr

  • esr-previous :new_button:

  • release :new_button:

  • release-previous :new_button:

(Помните, согласно предыдущей иллюстрации, это только два из трех, потому что esr-previous поддерживается, новый esr совпадает с release или release-previous, и мы прекращаем поддержку esr-previous, когда это перестает быть верным).

При внедрении исправления безопасности в latest тег latest-security-fix будет автоматически перемещен на этот коммит. docker_manager будет обновлен для отслеживания этого тега и предложения администраторам обновиться. Это позволяет нам выпускать и уведомлять об исправлениях безопасности без необходимости ускоренного обновления версии.

Переводы

В настоящее время ветки stable и tests-passed можно переводить в CrowdIn, и результаты регулярно интегрируются. В новой системе мы изначально планируем сделать latest и release переводимыми в CrowdIn.

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

Совместимость плагинов и тем

Увеличение использования потоков Discourse, отличных от latest, усилит нашу зависимость от системы discourse-compatibility. Поэтому нам потребуются улучшения в этой системе совместимости.

Вместо использования файла .discourse-compatibility в ветке main, мы могли бы поддерживать неявную совместимость на основе специально именованных веток/тегов. Это должно быть намного проще, чем вручную управлять хешами коммитов. Например, плагин может иметь ветки, такие как:

  • d-compat/v2026.1
  • d-compat/v2026.2
  • d-compat/v2026.3
  • main (используется для любой версии Discourse, у которой нет своей ветки)

При установке плагина Discourse может проверить наличие ветки, соответствующей текущей версии. Если она существует, проверить её. В противном случае проверить файл .discourse-compatibility. В противном случае проверить ветку по умолчанию.

Мы можем создать публичное действие GitHub, которое ежедневно запускается для каждой темы/плагина, проверяет новые релизы Discourse и автоматически создает эти ветки. Каждая тема/плагин может выбрать использование этого действия для автоматического привязывания или предпочесть более «плавающую» стратегию.

Хостинг discourse.org

Изначально наше хостинговое предложение будет продолжать использовать версию latest Discourse. В будущем мы будем исследовать возможности для клиентов корпоративного уровня выбирать версию «release».

Настройки по умолчанию для стандартной установки

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

Я немного запутался. То есть tests-passed, он же latest (что, как я предполагаю, является вариантом по умолчанию), будет самым актуальным (получать самые частые обновления; в этом ничего не меняется), но текущая ветка beta, теперь ветка release, будет вести себя так же, как и сейчас, то есть представлять собой «группу» коммитов/обновлений, а затем ветка ESR (он же stable) будет представлять собой большую «группу» обновлений из beta/release?

Означает ли это, что release теперь становится вариантом по умолчанию, или когда вы говорите «последний релиз», вы имеете в виду «последнее обновление в ветке release»? Будет ли тогда разница между этим и latest?

Спасибо!

В настоящее время beta — это тег, и в него не включаются исправления, перенесённые из других версий.

С этим предложением каждая версионированная версия будет иметь свою собственную ветку и будет получать исправления безопасности, пока она «поддерживается». Пользователи смогут указывать при установке конкретный номер версии и продолжать её использование даже после выпуска новой версии. В текущей ситуации это невозможно ни с beta, ни с stable.

release будет тегом, который следует за последним выпуском (включая патч-релизы) для получения исправлений безопасности.

Нет:

«Последний релиз» (или просто «release») = самый свежий коммит в самой последней ветке релиза.

«latest» = новое название для состояния, когда тесты пройдены.

Спасибо, теперь всё понятно!

Это выглядит как позитивное развитие событий!

Будет ли проводиться какое-либо специальное тестирование обновлений с esr-previous до esr в момент, когда esr получает соответствующую метку? Такие обновления, на мой взгляд, должны быть организованы так, чтобы они проходили гладко, либо должны содержать подробные описания того, как выполнить их максимально плавно.

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

Только небольшая просьба для удобства: не могли бы вы привязать указатель версии (например, 2026.0) к месяцу выхода релиза? (т. е. 2026.01 для января, 2026.02 для февраля и т. д.)

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

Проект, который я активно использую (mailcow), пропускает месяц, если в ядре не произошло значительных изменений.

И отсчёт с нуля был бы очень странным. Это имеет смысл для программистов, но не очень понятно для нетехнических людей.

Редактирование:

Вы должны иметь возможность использовать версию 2026.02.x для нескольких релизов в течение месяца и легко переходить с 02 на 04. Главное, чтобы нумерация оставалась последовательной?

Мне интересно насчёт упомянутого релиза x.0. Мне очень нравится привязка к месяцу, чтобы сразу было понятно, когда вышел релиз. Но, возможно, не так важно, вышел ли xx.8 в сентябре, декабре или июне. Я с трудом помню, на каком сейчас релизе мы находимся, поэтому было бы очень удобно сразу видеть, о баге ли из прошлой недели или нескольких месяцев назад идёт речь, не прибегая к просмотру коммита, как я делаю сейчас.

В Ubuntu используются версии YY.04 и YY.10. Это работает уже двадцать лет. Пропуск месяцев, похоже, не такая уж сложная задача.

Это, пожалуй, более серьёзная проблема, хотя, если бы пришлось выпускать две версии в месяц, можно было бы использовать что-то вроде 22.1a или 22.01a.

Некоторое время назад мы также начали использовать эту стратегию для нашей платформы. Всё точно так же, включая ветвление и применение патчей. Я могу это рекомендовать.

Мы выпускаем обновления ежемесячно. Поэтому нумерация идёт от 1 до 12. Такой ритм помогает всем. Всегда есть что выпустить (привет, Dependabot), и никому не хочется делать слияние веток дважды в месяц. Кроме того, когда я говорю: «Я использую версию 2025.6», все понимают, что речь идёт о версии, выпущенной до летних каникул.

Тем не менее, я вполне доволен текущим процессом :slight_smile:

Прежде всего, :rocket: это отличный шаг!

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

  1. git branch и многие другие инструменты не понимают версионирование и сортируют ветки по алфавиту или числам. В обоих случаях 2026.10 окажется между 2026.1 и 2026.2. Вдохновившись Ubuntu, я предлагаю добавлять ведущий ноль для релизов и патч-релизов, когда номер состоит из одной цифры. Тогда у нас будут v2026.01, v2026.02 и v2026.10, и вселенная снова станет счастливой.

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

Итак, если я реализую новую функцию в своём плагине, требующую v2026.3, я создам ветку и помещу туда новую функциональность. Теперь, когда функция готова и мой клиент доволен, я могу немного отдохнуть и насладиться отпуском :palm_tree: :wine_glass:. Однако после третьего бокала вина вы решаете выпустить v2026.4, а мой клиент решает обновиться. И бац — в моём плагине нет ветки v2026.4, и функциональность исчезает :sob:.

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

На самом деле всё наоборот. Ветки совместимости предназначены только для «выпущенных» веток Discourse. Ветка Discourse latest всегда будет использовать ветку main вашего плагина. Именно там вы будете разрабатывать новые функции.

История будет выглядеть так:

Discourse выпускает v2026.2. GitHub Actions в вашем плагине автоматически обнаруживает это и создаёт ветку d-compat/v2026.2. Теперь любой, кто использует Discourse v2026.2, будет использовать версию вашего плагина d-compat/v2026.2.

Вы выпускаете новую функцию в ветке main вашего плагина. Вам не нужно думать о обратной совместимости, потому что ветка main используется только теми, кто работает с версией Discourse latest.

Затем, пока вы потягиваете свой третий бокал вина :wine_glass:, Discourse выпускает v2026.3. Изначально для этой версии нет ветки плагина, поэтому будет использоваться main. Всё продолжает работать так же, как и для пользователей ветки latest.

В течение нескольких часов ваш GitHub Action обнаруживает новую версию и фиксирует ветку d-compat/v2026.3, готовую к тому, чтобы следующая функция вашего плагина была добавлена в main без необходимости заботиться о обратной совместимости.

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

Это здорово, спасибо за подробное объяснение.

Похоже, я могу выпить четвёртый бокал вина :wink:

Поддерживаю сказанное другими — мне нравится направление предлагаемых изменений. И считаю, что предложенные названия веток гораздо более интуитивны, чем старые :+1:

Пока не совсем понятно, как будет работать процесс обновления для веток release и esr (latest выглядит вполне очевидно). Вы упоминаете, что в любой момент времени будут поддерживаться как текущий выпуск (назовём его n), так и предыдущий (n-1), и что как администратор я смогу выбрать, когда выполнять обновление.

Исходя из моего опыта работы с другим ПО, когда появляется новая версия (n+1), я получаю уведомление о её доступности. Затем я могу решить: выполнить крупное обновление (аналог apt dist-upgrade в Linux) или обычное/стандартное обновление (аналог apt upgrade в Linux), оставшись на версии n. Будет ли такая возможность реализована в скрипте запуска Discourse?

Также я понимаю стремление минимизировать церемонию и процесс выпуска релизов, но моя интуиция подсказывает, что как обычные, так и ESR-выпуски должны проходить хотя бы минимальное дополнительное тестирование перед релизом. Возможно, это следствие слишком долгой работы в корпоративном IT :smile:

Наконец, я задаюсь вопросом, не являются ли ежемесячные релизы слишком частыми. Признаю, что это тоже субъективно, но, судя по моему опыту волонтёрского управления IT-инфраструктурой, у меня может не хватать времени на крупные обновления каждый месяц. Исходя из этого, я подумал: не было бы проще облегчить жизнь разработчикам Discourse, выпустив релизы ежеквартально, убрав отдельные ветки esr и оставив только ветки release?

Это усложнит жизнь разработчикам тем и плагинов, потому что в такой (этой) ситуации на них ложится давление необходимости обновлять свои темы и плагины, иначе они не получат обновлений безопасности. Версия ESR снимет это давление.

Не уверен, что полностью понял. Исходя из предыдущих сообщений, я думал, что создание ветки релизной версии автоматически запускает создание ветки плагина для этой версии. Поэтому я предполагал, что объединение release и esr в одну ветку также сократит усилия для создателей плагинов и тем, поскольку при необходимости внести исправление их нужно будет выгружать в меньшее количество веток (три вместо пяти). Но, возможно, я что-то упускаю?

Дело не в том, когда автор темы или плагина выпускает исправление, а в том, когда ядро Discourse получает исправление безопасности.

Согласно

единственное различие между release и esr заключается в том, что esr получает исправления безопасности в течение 6 + 2 = 8 месяцев.

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

  1. Релиз v2026.02
  2. Вы указываете version: release/v2026.02 в файле app.yml
  3. Релиз v2026.03
  4. Вы запускаете пересборку. Вы всё ещё получаете версию 2026.02, но с последними исправлениями безопасности
  5. Когда будете готовы, переключитесь на version: release/v2026.03 в app.yml

Однако ручное редактирование файла app.yml каждый месяц — это далеко не идеальный вариант, поэтому мы надеемся разработать систему, которая сделает процесс более удобным для пользователя.

Процесс, описанный в оригинальном посте, позволяет нам рассматривать ветки как «кандидаты в релизы» перед тем, как официально объявлять их релизами. Пока точно неясно, как именно мы будем использовать эту возможность — думаю, это будет определяться по мере того, как мы привыкнем к новой системе.

Мы пытаемся найти баланс между скоростью разработки Discourse и стабильностью для пользователей с обширными кастомизациями. Задержка в 3+ месяца перед тем, как новые функции попадут к нашим клиентам, недопустима. Более того, для нас ежемесячные релизы даже кажутся медленными. В настоящее время мы по-прежнему планируем использовать ветку latest для большинства наших хостинг-решений.

Но, конечно, для тех, кто самостоятельно размещает Discourse, я понимаю желание иметь менее частые изменения. Именно здесь и приходят на помощь ESR-релизы.

Здесь всё зависит от автора плагина или темы. Либо они могут продолжить текущую стратегию, когда ветка main плагина должна работать со всеми «релизными» версиями Discourse. Либо они могут использовать стратегию автоматического ветвления, которая упрощает совместимость, но также означает, что вам, возможно, придётся выполнять много «бэкпортирования» в вашем плагине в случае критических исправлений ошибок или уязвимостей безопасности.

В любой момент времени существует три «поддерживаемые» версии Discourse, плюс latest. Таким образом, критические исправления необходимо применять в до 4 веток.