扩展版本控制
大多数软件都有某种版本号。版本号主要实现以下几个重要目标:
- 将二进制文件与源代码的特定状态绑定
- 允许确定预期的功能集
- 允许确定 API 的状态
- 允许高效处理错误报告(例如,错误
#1337是在v3.4.5版本中引入的) - 允许确定发布的先后顺序(例如,版本
v1.2.3早于v1.2.4) - 提供预期稳定性的指示(例如,
v0.0.1可能不太稳定,而v13.11.0可能非常稳定)
正如 DuckDB 本身一样,DuckDB 扩展也有自己的版本号。为了确保这些版本号在各个扩展中具有一致的语义,DuckDB 的 核心扩展 (Core Extensions) 使用了一套规定扩展版本命名方式的版本控制方案。核心扩展的版本控制方案由 3 个不同的稳定性级别组成:不稳定 (unstable)、预发布 (pre-release) 和 稳定 (stable)。让我们逐一了解这 3 个级别并描述它们的格式。
不稳定扩展
不稳定扩展是指那些无法(或不愿)就其当前稳定性或其实现稳定的目标做出任何保证的扩展。不稳定扩展使用该扩展的 短 git 哈希值 进行标记。
例如,在撰写本文时,vss 扩展的版本是一个版本号为 690bfc5 的不稳定扩展。
对于具有 不稳定 格式版本号的扩展,可以预期什么?
- 可以通过在扩展仓库中查找哈希值来找到扩展源代码的状态
- 功能可能会在每次发布时发生变化或被完全移除
- 该扩展的 API 可能会在每次发布时发生变化
- 该扩展可能不遵循结构化的发布周期,新的(破坏性)版本随时可能被推送
预发布扩展
预发布扩展是继不稳定扩展之后的下一个级别。它们使用 SemVer 格式进行标记,更具体地说是 v0.y.z 格式。在语义版本控制中,以 v0 开头的版本具有特殊含义:它们表明常规 (>v1.0.0) 版本中更严格的语义尚未适用。这基本上意味着扩展正在朝着稳定扩展的方向努力,但尚未完全达到目标。
例如,在撰写本文时,delta 扩展的版本是一个版本为 v0.1.0 的预发布扩展。
对于具有 预发布 格式版本号的扩展,可以预期什么?
- 扩展是从对应于该标签的源代码编译而来的。
- 适用语义版本控制语义。详细信息请参阅 语义版本控制 规范。
- 该扩展遵循一个发布周期,即在分组成发布并推送到
core仓库之前,新功能会在每日构建 (nightly builds) 中进行测试。 - 应该提供描述每次发布新增内容的发行说明,以便于理解版本之间的差异。
稳定扩展
稳定扩展是扩展稳定性的最后阶段。这通过使用格式为 vx.y.z(其中 x>0)的 稳定版 SemVer 来表示。
例如,在撰写本文时,parquet 扩展的版本是一个版本为 v1.0.0 的稳定扩展。
对于具有 稳定 格式版本号的扩展,可以预期什么?本质上与预发布扩展相同,但现在适用了更严格的 SemVer 语义:扩展的 API 现在应该是稳定的,并且只有在主版本号提升时才会以向后不兼容的方式更改。详细信息请参阅 SemVer 规范。
预发布和稳定核心扩展的发布周期
通常情况下,扩展的发布周期取决于其稳定性级别。不稳定 扩展通常与 DuckDB 的发布周期保持同步,但也可能在 DuckDB 发布版本之间静默更新。预发布 和 稳定 扩展遵循它们自己的发布周期。这些周期可能与也可能不与 DuckDB 的发布周期一致。要了解特定扩展的发布周期,请参考相应扩展的文档或 GitHub 页面。通常,预发布 和 稳定 扩展会将它们的版本记录为 GitHub Releases,您可以在 delta 扩展 中看到一个例子。
最后,有一个小的例外:所有 树内 (in-tree) 扩展仅遵循 DuckDB 的发布周期。
每日构建 (Nightly Builds)
正如 DuckDB 本身一样,DuckDB 的核心扩展也有每日构建或开发版本,可用于在正式发布前试用功能。当您的工作流程依赖于新功能,或者您需要确认您的技术栈与即将发布的版本兼容时,这非常有用。
扩展的每日构建稍微复杂一些,因为目前 DuckDB 扩展二进制文件与特定的 DuckDB 版本紧密绑定。由于这种紧密联系,存在组合爆炸的潜在风险。因此,并非所有扩展的每日构建版本和 DuckDB 每日构建版本的组合都是可用的。
通常,使用每日构建版本有两种方式:使用每日构建版的 DuckDB 和使用稳定版的 DuckDB。让我们看看两者之间的区别。
使用稳定版 DuckDB
在大多数情况下,用户会对特定扩展的每日构建版本感兴趣,但不一定想切换到使用 DuckDB 本身的每日构建版本。这允许在限制接触不稳定代码的同时使用特定的前沿功能。
为了实现这一点,核心扩展倾向于定期向 core_nightly 仓库 推送构建。让我们看一个例子。
首先,我们安装一个 稳定版的 DuckDB。
然后,我们可以像这样安装并加载一个 每日构建 (nightly) 扩展:
INSTALL aws FROM core_nightly;
LOAD aws;
在这个例子中,我们使用 aws 扩展的最新 每日构建 版本和 DuckDB 的最新 稳定 版本。
使用每日构建版 DuckDB
当 DuckDB 的 CI 生成 DuckDB 本身的每日二进制文件时,这些二进制文件会与一组固定了特定版本的扩展一起分发。此扩展版本将针对该特定版本的 DuckDB 进行测试,但这可能不是最新的开发版本。让我们看一个例子。
首先,我们安装一个 每日构建版的 DuckDB。然后,我们可以按预期安装并加载 aws 扩展。
INSTALL aws;
LOAD aws;
更新扩展
DuckDB 有一个专门的语句,可以自动将所有扩展更新到它们的最新版本。输出将为用户提供有关哪些扩展已更新至(或来自)哪个版本的信息。例如:
UPDATE EXTENSIONS;
| 扩展名称 | repository (仓库) | update_result (更新结果) | previous_version (先前版本) | current_version (当前版本) |
|---|---|---|---|---|
| httpfs | core | NO_UPDATE_AVAILABLE (无可用更新) | 70fd6a8a24 | 70fd6a8a24 |
| delta | core | UPDATED (已更新) | d9e5cc1 | 04c61e4 |
| azure | core | NO_UPDATE_AVAILABLE (无可用更新) | 49b63dc | 49b63dc |
| aws | core_nightly | NO_UPDATE_AVAILABLE (无可用更新) | 42c78d3 | 42c78d3 |
请注意,DuckDB 将在每个扩展的源仓库中查找更新。因此,如果扩展是从 core_nightly 安装的,它将使用最新的每日构建版本进行更新。
update 语句还可以提供一个要更新的特定扩展列表。
UPDATE EXTENSIONS (httpfs, azure);
| 扩展名称 | repository (仓库) | update_result (更新结果) | previous_version (先前版本) | current_version (当前版本) |
|---|---|---|---|---|
| httpfs | core | NO_UPDATE_AVAILABLE (无可用更新) | 70fd6a8a24 | 70fd6a8a24 |
| azure | core | NO_UPDATE_AVAILABLE (无可用更新) | 49b63dc | 49b63dc |
目标 DuckDB 版本
目前,在编译扩展时,它们被绑定到特定的 DuckDB 版本。这意味着,例如,为 0.10.3 版本编译的扩展二进制文件无法在 1.0.0 版本中工作。在大多数情况下,这不会导致任何问题,并且是完全透明的;DuckDB 将自动确保为其版本安装正确的二进制文件。对于扩展开发者而言,这意味着他们必须确保在 DuckDB 的每个新版本发布时创建新的二进制文件。但是,请注意 DuckDB 提供了一个 扩展模板,这使得操作相当简单。
树内 (In-Tree) 与 树外 (Out-of-Tree)
最初,DuckDB 扩展完全存在于 DuckDB 主仓库 github.com/duckdb/duckdb 中。这些扩展被称为树内扩展。后来,引入了树外扩展的概念,将扩展分离到它们自己的仓库中,我们称之为树外。
虽然从用户的角度来看,通常没有什么明显的区别,但在版本控制方面有一些细微的差异:
- 树内扩展使用 DuckDB 的版本,而不是拥有自己的版本。
- 树内扩展没有专门的发行说明,它们的更改反映在常规的 DuckDB 发行说明 中。
- 核心树外扩展往往位于名为
github.com/duckdb/duckdb-extension_name的仓库中,但名称可能会有所不同。有关详细信息,请参阅核心扩展的 完整列表。