RFC:Discourse 的新版本策略

我们计划为 Discourse 引入新的版本控制系统。我们的目标是在保持开发速度的同时,为社区管理员提供更多的选择和可预测性。我们还将调整一些术语,使其与其他软件更好地对齐。

随着我们收到反馈、开始实施该系统以及随后扩展新发布流的使用,本文档将不断更新。

如果您在此阶段有任何意见/建议,请回复此主题告知我们!


目标

  1. 为 Discourse 引入更常规的“发布”,在开发速度和稳定性之间取得平衡。

  2. 继续提供大约每 6 个月一次的发布,并提供延长支持。

  3. 为常规发布和长期支持发布提供重叠支持,以便管理员在更新时间上拥有更大的灵活性,同时继续接收关键安全更新。

  4. 尽量减少“发布”的仪式。尽可能自动化,并且不应减慢核心开发人员的体验。ESR 发布与其他任何发布一样。

  5. 命名和流程应符合行业标准,以便更容易向开发人员和最终用户解释。

高层概述

  • 大约每月发布一次。‘主’版本是当前年份,‘次’版本每次发布递增。对于任何回溯修复,补丁版本号将递增。

    例如,2026 年的第一个版本将是 v2026.0,下一个是 v2026.1,依此类推。

    发布将获得两个完整发布周期的关键修复。例如,2026.0 的支持将持续到发布 2026.2

  • 大约每 6 个月,将其中一个发布声明为长期支持发布 (ESR)。ESR 版本在下一个 ESR 声明后仍受支持两个发布周期。

    例如,如果 v2026.0 是 ESR,v2026.6 是下一个 ESR,那么 v2026.0 的支持将在 v2026.8 发布时结束。假设每月一次的节奏,这将是 ESR 支持的 2 个月重叠。

  • latest、最新发布、前一个发布和任何活动的 ESR 版本提供关键修复。

  • tests-passed 分支重命名为 latest

一年中支持周期的示例图:

gantt
    title Discourse 发布和支持周期 (2026 年 1 月 – 2027 年 1 月)
    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.0v2026.1.1 等。

  • 最新发布将被标记为 release。最新的 ESR 将被标记为 esr

  • 前一个发布将被标记为 release-previous。前一个活动的 ESR(如果有)将被标记为 esr-previous

  • 为了向后兼容,与现有发布流匹配的标签将被别名化为最接近的新等效项。stableesrbetareleasetests-passedlatest

    这些将被视为已弃用,我们将致力于在未来删除其中一些或全部。特别是,“beta”是有问题的,因为它给人一种 Discourse 未准备好生产的印象。

  • latest 上,版本号将是当前正在开发的版本,后缀为 -latest。例如 2026.3.0-latest

自动化发布流程

每月,一个 GitHub action 将打开一个新的 PR,其中包含一个将 main 上的 version.rb 提升到下一个 -latest 版本的提交。

一旦有人合并了 PR,另一个 GitHub action 将检测到 main 已更新到下一个 -latest 版本,并为已完成的发布创建一个分支。本质上,这个分支将成为一个“发布候选”。另一个自动化 PR 将针对发布分支打开,更新 version.rb 以删除 -latest 后缀,从而“发布”它。

通常,我们会快速连续合并这两个 PR。但是,将创建和最终发布分开的 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 actions 工作流将监视发布分支上的任何回溯提交。当找到任何提交时,将生成一个新的 PR 来提升该分支上的补丁版本。人工可以决定何时合并这些 PR。

所有这些自动化都将自动保持各种标签(releaserelease-previousesresr-previous,以及向后兼容的别名)的最新状态。

安全修复

安全修复工作流程基本保持不变,只是我们现在需要在以下三个新位置中的两个位置进行修复:

  • latest

  • esr

  • esr-previous :new_button:

  • release :new_button:

  • release-previous :new_button:

(请记住,根据之前的图示,只需要三个中的两个,因为 esr-previous 是受支持的,新的 esrreleaserelease-previous 相同,并且在不再适用时我们将停止支持 esr-previous)。

在将安全修复引入 latest 时,latest-security-fix 标签将自动移至该提交。docker_manager 将被更新以监视该标签并提示管理员进行更新。这使我们能够在不需要加速版本升级的情况下发布和通知安全修复。

翻译

目前,stabletests-passed 分支可以在 CrowdIn 中进行翻译,并且结果会定期集成。在新系统中,我们最初计划让 latestrelease 在 CrowdIn 中进行翻译。

理想情况下,当 release 变为 release-previousesr 时,翻译将已稳定。如果对这些版本的持续翻译有需求,那么这将在未来可以考虑。

插件/主题兼容性

增加使用非 latest Discourse 流的频率将增加我们对 discourse-compatibility 系统的依赖。因此,我们需要对兼容性系统进行一些改进。

我们可以使用特殊命名的分支/标签来支持隐式兼容性,而不是在 main 上使用 .discourse-compatibility 文件。这应该比手动处理提交哈希更容易。例如,一个插件可以有如下分支:

  • d-compat/v2026.1
  • d-compat/v2026.2
  • d-compat/v2026.3
  • main(用于任何没有自己分支的 Discourse 版本)

安装插件时,Discourse 可以检查是否存在与当前版本匹配的分支。如果存在,则检出该分支。否则,检查 .discourse-compatibility 文件。否则,检出默认分支。

我们可以创建一个公共 GitHub action,该 action 每天在每个主题/插件上运行,检查新的 Discourse 版本,并自动创建这些分支。每个主题/插件可以选择使用此自动固定操作,或者选择更“浮动”的策略。

discourse.org 托管

最初,我们的托管服务将继续运行最新版本的 Discourse。未来,我们将探索为我们的企业级客户选择“发布”版本的选项。

标准安装默认值

最初,默认值仍将是 latest。管理员将能够选择加入新的发布流,就像他们目前选择加入 stable 一样。一旦系统更加成熟,我们可能会在未来探索在发布流之间进行更轻松的切换。

38 个赞

我有点困惑。那么 tests-passedlatest(我假设这是默认值)将是最新的(接收最频繁的更新;这方面没有变化),但当前的 beta 分支,现在是 release 分支,将仍然像现在一样运行,即一个“组”的提交/更新,然后 ESR(即 stable)分支将是更大的“组”的 beta/release 更新?

这是否意味着 release 现在成为默认选项,或者当你提到“最新发布”时,你指的是“release 分支上的最新更新”?那么它和 latest 之间会有区别吗?

谢谢!

1 个赞

beta 当前是一个标签,不接收任何回溯修复。

根据此提议,每个版本化的发布都将有自己的分支,并在其“受支持”期间接收安全修复。用户可以选择将其安装指向特定的版本号,并在发布新版本后继续使用它。这在使用当前的 betastable 时是不可能的。

release 将是一个标签,用于跟踪最新的发布(包括补丁发布),以进行安全修复。

不:

“最新发布”(或简称为“发布”)= 最新发布分支上的最新提交

“latest” = tests-passed 的新名称

3 个赞

谢谢,这样就清楚了!

2 个赞

这看起来是个积极的发展!

在 esr 被标记时,是否会进行从 esr-previous 到 esr 的特定升级测试?我认为,这类升级应该被安排为平滑升级,或者提供如何尽可能顺利地执行它们的详细说明。

4 个赞

是的,ESR 版本之间的升级(或者任何支持版本之间的升级)将继续无缝进行。

2 个赞

为了方便起见,能否将指针(例如 2026.0)与发布推送的月份关联起来?(即 2026.01 代表一月,2026.02 代表二月等)

4 个赞

将事物明确地与月份绑定会带来问题,因为这样我们就无法跳过某个月份,或者在一个月内发布两个版本。这就是为什么我们计划将其保留为一个简单的递增数字。

3 个赞

我重度使用的一个项目(mailcow)会在没有重大核心更改时跳过月份。

从 0 开始计数会非常奇怪。这对程序员来说很有意义,但对非技术人员来说意义不大。

2 个赞

我一直在想提到的 x.0 版本。我真的很喜欢将其与月份联系起来,这样您就可以立即知道发布时间。但也许 xx.8 是在 9 月、12 月还是 6 月发布的并不重要。不过,我几乎不记得我们现在用的是哪个版本了,所以如果能立即知道某人是在谈论上周还是几个月前的错误,而不用像现在这样去查看提交记录,那将是很棒的。

Ubuntu 有 YY.04 和 YY.10。这已经行得通二十年了。跳过月份似乎并不难。

不过,这似乎是个更大的问题,但如果你必须在一个月内发布两个版本,你可以做类似 22.1a 或 22.01a 的事情。

6 个赞

不久前,我们也开始为我们的平台使用这种策略。包括分支和补丁在内的所有方面都完全相同。我推荐它。

我们按月发布。所以有 1-12。这种节奏对每个人都有帮助。总有东西要发布,而且没有人想一个月分支两次。另外,当我说的“我使用 2025.6”时,每个人都知道这是夏令营之前的版本。

7 个赞

首先,: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

9 个赞

意图是相反的。兼容分支仅用于 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 将它们冻结。这个基于分支的提议旨在成为该工作流程的一个更轻量级的版本。

16 个赞

这太棒了,感谢您详细的解释。

听起来我可以再喝第四杯葡萄酒;)

15 个赞

我同意其他人的说法,我喜欢拟议变更的方向。而且我认为提议的分支名称比旧的更直观 :+1:

对我来说还不清楚的是 releaseesr 分支的升级过程将如何进行(latest 似乎很简单)。您提到,在任何时间点,当前版本(我们称之为 n)和前一个版本(n-1)都将得到支持,并且作为管理员,我将可以选择何时升级。

根据我使用其他软件的经验,当新版本(n+1)到达时,我会收到版本 n+1 可用性的通知。然后,我可以选择进行主要升级(相当于 Linux 上的 apt dist-upgrade)或进行次要/标准更新(相当于 Linux 上的 apt upgrade)并停留在版本 n。这是否会被纳入 Discourse 启动器脚本?

另外,我理解您希望尽量减少发布仪式/流程,但我的直觉是,正常版本和 esr 版本在发布前至少会经过一些额外的测试。这可能是我长期从事企业 IT 工作造成的 :smile:

最后,我想知道每月发布是否真的“太快了”。这当然也是主观的,但根据我作为志愿者管理 IT 方面的经验,我可能没有时间每月进行较大的更新。基于此,我想知道您是否可以通过简单地每季度发布一次,并且不设单独的 esr 分支,只设 release 分支,来让您作为 Discourse 开发者的生活更轻松一些。

4 个赞

这会让主题和插件的开发者生活更艰难,因为在这种(这种情况)下,你们会面临更新主题和插件的时间压力,否则将无法获得任何安全更新。ESR 版本将减轻这种压力。

4 个赞

我不确定我是否完全理解。根据之前的帖子,我的理解是创建发布版本分支会自动创建该版本的插件分支。所以我的假设是,将 releaseesr 合并为一个也会减少插件和主题构建者的工作量,因为任何时候您需要推送一个修复程序,它都需要推送到更少的分支(三个而不是五个)。但也许我遗漏了什么?

2 个赞

这与主题/插件作者何时推送修复无关,而与 Discourse 核心何时有安全修复程序有关。

根据

releaseesr 之间的唯一区别是 esr 可以获得 6 + 2 = 8 个月的安全修复。

1 个赞

使用当前的启动器工具和这个新的分支结构,您可以通过以下方式控制升级时间:

  1. 发布 v2026.02
  2. 在您的 app.yml 文件中设置 version: release/v2026.02
  3. 发布 v2026.03
  4. 运行重建。您仍然会获得 2026.02 版本,并包含任何最近的安全修复程序
  5. 准备好后,在 app.yml 中切换到 version: release/v2026.03

但是,每个月手动编辑 app.yml 并不是理想的选择,所以希望我们能够设计一个更用户友好的系统。

OP 中的流程确实允许我们将分支视为“候选版本”,然后再实际将其标记为发布版本。我还不确定我们是否/如何在此阶段使用该功能 - 我认为这会随着我们适应新系统而不断发展。

我们正在努力平衡 Discourse 的开发速度和对拥有大量自定义的用户来说的稳定性。让客户在 3 个月或更长时间后才能获得新功能是不可行的。如果说有什么不同的话,对我们来说,每月发布的速度算是慢的了。目前我们仍然打算在大多数托管中使用 latest

但是,对于那些自己托管 Discourse 的用户来说,我理解他们希望减少更改频率的愿望。这就是 ESR 版本的作用所在。

5 个赞

这取决于插件/主题作者。他们可以继续当前的策略,即插件的 main 分支需要与所有“已发布”版本的 Discourse 一起使用。或者,他们可以使用自动分支策略,这使得兼容性更容易,但也意味着在出现任何关键错误/安全修复时,您可能需要在插件中进行大量“回溯移植”。

在任何给定时间,都有三个“支持”版本的 Discourse,外加 latest。因此,关键修复程序需要应用于最多 4 个分支。

3 个赞