本文概述了 DuckDB 及其核心扩展的发布周期框架。旨在帮助从事 DuckDB 扩展开发的开发者更好地理解相关流程。
概览
- DuckDB 遵循 语义化版本控制 (
v<MAJOR>.<MINOR>.<PATCH>) - 小版本(Minor versions)大约每 4 个月发布一次
- 补丁版本(Patch releases)根据需要针对以下情况发布:
- 最新的稳定版本
- 当前的长期支持(LTS)版本
- 所有发布版本均列于 发布日历 中
术语
在发布文档中,我们使用一些基本术语来描述版本和分支。此处作简要说明。
vx.y.z: 最新的稳定版本vx.y-codename: 将生成vx.y.<n>版本的发布分支名称vx.<y+1>-codename: 用于生成下一个小版本的分支名称Main release cycle(主发布周期): 与生成vx.<y+1>.0和vx.y.<z+1>版本相关的分支、提交和 PRActive branch(活跃分支): 属于主发布周期的分支。即 main 或 n >= 0 的vx.<y+n>-codenameSingle branch extension(单分支扩展): 只有一个活跃分支的扩展。由于 main 始终是活跃分支,因此这种情况通常指 main。这意味着格式为vx.y-codename的所有其他分支必须是 n >= 1 的vx.<y-n>-codenameMulti branch extension(多分支扩展): 具有一个以上活跃分支的扩展Two branch extension(双分支扩展): 具有两个活跃分支的扩展:main 和vx.y-codenameThree branch extension(三分支扩展): 具有三个活跃分支的扩展:main、vx.y-codename和vx.<y+1>-codenameLTS release(长期支持版本): 长期支持版本。这些版本在其活跃发布周期结束之后仍将获得支持(补丁版本)。目前 LTS 版本将获得 1 年的支持Unstable API extension(不稳定 API 扩展): 针对不稳定扩展 API 的扩展。这可以是 C++ API 或不稳定的 C API。这些扩展在不同的 DuckDB 版本之间不具备二进制兼容性Stable API extension(稳定 API 扩展): 针对 DuckDB 稳定 C API 的扩展。这些扩展在不同的 DuckDB 版本之间具备二进制兼容性In-tree extensions(树内扩展): 位于duckdb/duckdb源码树中的扩展
主分支与标签
在基于 Git 的版本控制中,分支用于允许多个版本的代码库共存。在 DuckDB 中,有两个核心分支在 DuckDB(及其扩展)发布周期中起着主要作用。我们首先列出这些核心分支的格式。
main分支:main 分支可以有多种含义,但通常被认为是全能分支vx.y-codename分支:用于生成所有vx.y.z版本的分支vx.y.z标签:DuckDB 的稳定发布版本。这些标签是只写的,并将始终绑定到同一个提交
DuckDB 主发布周期
LTS(长期支持)版本遵循单独的维护周期,以提供扩展的支持和稳定性。
DuckDB 主发布周期由 3 个主要阶段组成:周期中期 (Mid-cycle)、预发布 (Pre-release) 和 功能冻结 (Feature freeze)。这些阶段定义明确且经过沟通,以确保整个团队同步并共同推进下一次发布。
阶段 1:周期中期 (Mid-Cycle)
活跃的 DuckDB 分支
mainvx.y-codename
描述
周期中期是发布周期中最常见的阶段,大约 75% 的时间处于此阶段。这可以看作是日常工作状态,距离即将到来的发布还有很长时间,团队正在努力合并各种功能和错误修复。在此阶段,补丁版本(vx.y.<z+n>)可能会从 vx.y-codename 分支创建。补丁会被合并到 vx.y-codename 分支,并且 vx.y-codename 分支会频繁合并到 main 分支,以保持两者同步。
DuckDB 的 PR 合并规则
vx.y.<z+n>补丁版本的错误修复合并到vx.y-codenamevx.<y+1>.0的功能和错误修复合并到main
阶段 2:预发布 (Pre-Release)
活跃分支
mainvx.y-codenamevx.<y+1>-codename
描述
预发布阶段旨在为即将到来的 vx.<y+1>.0 小版本发布做准备。在此阶段开始时,创建 vx.<y+1>-codename 分支。该分支将用于生成即将到来的小版本,并且是所有后续 vx.<y+1>.<n> 补丁版本的发布来源分支。
DuckDB 的 PR 合并规则
vx.y.<z+1>补丁版本的错误修复合并到vx.y-codenamevx.<y+1>.0的功能和错误修复合并到vx.<y+1>-codenamevx.<y+2>.0的功能合并到vx.<y+2>-codename
阶段 3:功能冻结 (Feature Freeze)
活跃分支
mainvx.y-codenamevx.<y+1>-codename
描述
功能冻结阶段是发布前的最后一个阶段。在此阶段,不允许再将新功能合并到 vx.<y+1>-codename,仅允许合并错误修复。此阶段旨在确保即将发布版本的质量。在此阶段,团队会进行额外的测试和基准测试,同时通过禁止功能合并来降低引入临时错误的风险。
DuckDB 的 PR 合并规则
- 不再允许针对
vx.y.<z+1>的错误修复,应改为针对vx.<y+1>.0 vx.<y+1>.0的错误修复合并到vx.<y+1>-codename- 不再允许针对
vx.<y+1>.0的功能合并,应改为针对vx.<y+2>.0 vx.<y+2>.0的功能合并到vx.<y+2>-codename
扩展的主发布周期
大多数 DuckDB 扩展与主 duckdb/duckdb 仓库完全独立,可以自由遵循自己的发布周期。在本节中,我们将 DuckDB 扩展归类,并讨论它们的发布周期。
为了描述扩展的发布周期,我们需要首先将扩展分为三类,因为扩展共享的发布周期取决于它们所属的类别。
- 树内扩展 (In-tree extensions)
- 不稳定 API 扩展 (Unstable API extensions)
- 稳定 API 扩展 (Stable API extensions)
现在,我们将按照复杂性增加的顺序介绍这三类扩展的发布周期。
树内扩展
对于树内扩展,发布周期非常简单。由于其代码存在于 duckdb/duckdb 仓库中,它们与 DuckDB 保持完全同步。这意味着它们共享相同的版本控制和分支。从这个意义上讲,它们并不是真正的扩展,更多是 duckdb/duckdb 代码库中可延迟加载的部分。
稳定 API 扩展
稳定 API 扩展在 DuckDB 中是一个相对较新的概念,但计划在未来成为大多数扩展的形式。稳定 API 扩展建立在稳定的 C 扩展 API 之上,使其与多个版本的 DuckDB 二进制兼容。这意味着它们的发布周期可以/应该完全独立于 DuckDB 的发布周期。
虽然稳定 API 扩展的发布周期仍在完善中,但基本思路是其发布周期由一个与 duckdb/duckdb 类似但独立的周期组成,其中每个版本将针对一个或多个 DuckDB 版本。
不稳定 API 扩展
不稳定 API 扩展目前占 DuckDB 扩展的大多数。这些扩展要么针对 C++ 扩展 API,要么针对不稳定 C 扩展 API。从发布周期的角度来看,它们是最复杂的。不稳定 API 扩展的每个版本仅针对单个 DuckDB 版本。这种 1:1 的绑定关系意味着这些扩展的发布周期往往需要在主 DuckDB 发布周期周围进行复杂的协调。虽然目标是将尽可能多的扩展迁移到稳定 API,但我们预计不稳定 API 扩展在相当长一段时间内仍将存在,因此有必要明确定义其生命周期。因此,我们将利用本节的其余部分进行详细描述。
按分支分类
首先,我们将不稳定 API 扩展划分为不同的子类别。正如 DuckDB 本身一样,这些扩展遵循与 DuckDB 相同的分支方案,其中 main 和 vx.y-codename 的组合起着主要作用。我们现在通过查看其活跃分支的数量来定义三种类型的不稳定扩展。
- 单分支扩展 仅具有
main活跃分支 - 双分支扩展 具有两个活跃分支:
main和vx.y-codename - 三分支扩展 具有三个活跃分支:
main、vx.y-codename和vx.<y+1>-codename
DuckDB 目标版本
每个不稳定 API 扩展都应针对单个 DuckDB 版本。此目标版本由 duckdb 子模块和 MainDistributionPipeline 工作流中的目标版本共同决定。扩展针对的版本取决于发布阶段和分支。我们现在讨论所有组合。
- 阶段:周期中期 (Mid-cycle)
- 类型:单分支
- 扩展
main->DuckDBvx.y.z或main
- 扩展
- 类型:双分支
- 扩展
main->DuckDBvx.y.z或main - 扩展
vx.y-codename->DuckDBvx.y.z或vx.y-codename
- 扩展
- 类型:三分支:不应存在
- 类型:单分支
- 阶段:预发布 (Pre-release) / 补丁 (Patch)
- 类型:单分支
- 扩展
main->DuckDBvx.y.z或vx.<y+1>-codename
- 扩展
- 类型:双分支
- 扩展
main->DuckDBvx.y.z或vx.<y+1>-codename - 扩展
vx.y-codename->DuckDBvx.y.z或vx.y-codename
- 扩展
- 类型:三分支
- 扩展
main->DuckDBmain - 扩展
vx.y-codename->DuckDBvx.y.z或vx.y-codename - 扩展
vx.<y+1>-codename->DuckDBvx.<y+1>-codename
- 扩展
- 类型:单分支
PR 合并位置
知道将 PR 合并到不稳定 API 扩展的位置取决于两件事:当前的发布阶段和扩展类型。我们现在讨论所有组合。
- 阶段:周期中期 (Mid-cycle)
- 类型:单分支
- 如果 DuckDB 目标为:
vx.y.z- 针对
vx.y.<z+1>的 PR 合并到main1 - 针对
vx.<y+1>.0的 PR 合并到main
- 针对
- 如果 DuckDB 目标为:
main- 针对
vx.y.<z+1>的 PR 是不可能的 - 针对
vx.<y+1>.0的 PR 合并到main
- 针对
- 如果 DuckDB 目标为:
- 类型:双分支
- 针对
vx.y.<z+1>的 PR 合并到vx.y-codename - 针对
vx.<y+1>.0的 PR 合并到main
- 针对
- 类型:三分支
- 针对
vx.y.<z+1>的 PR 合并到vx.y-codename - 针对
vx.<y+1>.0的 PR 合并到vx.<y+1>-codename - 针对
vx.<y+2>.0的 PR 合并到main
- 针对
- 类型:单分支
- 阶段:预发布 (Pre-release) / 补丁 (Patch)
改为针对小版本发布。
将发布什么版本的扩展?
每次 DuckDB 发布时,都应提供一套完整的所有核心扩展。对于不稳定 API 扩展,这意味着需要重新构建二进制文件。对于核心扩展,此构建通常通过 duckdb/duckdb CI 进行。这意味着发布时将提供的扩展列表记录在 扩展配置文件 中。但是,此配置文件可能并非总是最新的。为了决定扩展的哪个版本应包含在即将到来的版本中,我们基于发布类型(大/小版本)和扩展类型(单/多分支)定义了以下用于确定最新扩展版本的“事实来源”:
- 发布类型:补丁 (Patch)
- 扩展类型:单分支
- 最新版本:配置文件 中的提交
- 扩展类型:多分支
- 最新版本:扩展的
vx.y-codename分支
- 最新版本:扩展的
- 扩展类型:单分支
- 发布类型:小版本 (Minor)
- 扩展类型:单分支
- 最新版本:扩展的
main分支
- 最新版本:扩展的
- 扩展类型:双分支
- 最新版本:扩展的
main分支
- 最新版本:扩展的
- 扩展类型:三分支
- 最新版本:扩展的
vx.<y+1>-codename分支
- 最新版本:扩展的
- 扩展类型:单分支
在单分支、双分支和三分支之间切换
在不同的扩展分支类型之间切换是一个相当简单的过程,应按如下方式进行:
- 切换:单分支
->双分支- 时间:在任何阶段
- 原因
- 当希望合并不符合
vx.y.<z+1>标准的功能,同时又需要保持为vx.y.<z+n>进行发布的能力时 - 为了能够使用最新的 DuckDB main 进行测试,同时保持为
vx.y.<z+n>(包括vx.y.z本身)进行发布的能力
- 当希望合并不符合
- 操作
- 从
main分支的某个提交点创建vx.y-codename分支,该提交点介于main的 HEAD 与 DuckDBvx.y.z配置文件中的提交之间。
- 从
- 切换:双分支
->三分支- 时间:在预发布 (Pre-release) 或 功能冻结 (Feature-freeze) 阶段
- 原因
- 每当需要合并一个不符合合并到
vx.<y+1>.0标准的功能时。
- 每当需要合并一个不符合合并到
- 操作
- 从 main 创建
vx.<y+1>-codename分支
- 从 main 创建
- 切换:三分支
->双分支 或 双分支->单分支- 时间:作为从 功能冻结 (Feature Freeze)
->周期中期 (Mid-cycle) 过渡的一部分 - 操作:自动发生(
vx.y-codename定义上变为不活跃)
- 时间:作为从 功能冻结 (Feature Freeze)