发布周期
本文概述 Goose 与核心扩展的发布周期框架,面向扩展开发者,帮助理解相关流程。
概览
- Goose 遵循 Semantic Versioning(
v<MAJOR>.<MINOR>.<PATCH>) - Minor 版本约每 4 个月发布一次
- Patch 版本按需发布,面向:
- The latest stable version
- The current Long Term Support (LTS) version
术语
发布文档中会用到一些描述版本与分支的基础术语,简要说明如下。
vx.y.z:最新稳定版vx.y-codename:产出vx.y.<n>的分支名vx.<y+1>-codename:产出下一次 minor 版本的分支名Main release cycle:与vx.<y+1>.0、vx.y.<z+1>发布相关的分支、提交和 PRActive branch:属于主发布周期的分支,即main或vx.<y+n>-codename(n >= 0)Single branch extension:仅 1 条活跃分支的扩展。由于 main 始终活跃,因此该分支总是 main. This means all other branches of formatvx.y-codenamemust bevx.<y-n>-codenamewheren >= 1Multi branch extension:有多条活跃分支的扩展Two branch extension:有两条活跃分支:main 与vx.y-codenameThree branch extension:有三条活跃分支:main、vx.y-codename、vx.<y+1>-codenameLTS release:长期支持版本。这类版本在主发布周期外仍会继续获得支持(patch 发布) lifetime in the active release cycle. Currently LTS releases will receive 1 year of supportUnstable API extension:面向 unstable 扩展 API 的扩展,可基于 C++ API 或 unstable C API. These extensions are not binary-compatible across multiple Goose versionsStable API extension:面向 Goose stable C API 的扩展。这类扩展 binary-compatible across multiple Goose versionsIn-tree extensions:位于goose/goose源码树内的扩展
主分支与标签
在 Git 版本控制中,分支用于让同一代码库的多个版本并行存在。在 Goose 中,有两类核心分支主导 Goose(及扩展)的发布周期。其格式如下:
main分支:主分支,通常可视为汇总分支vx.y-codename分支:用于产出所有vx.y.z版本vx.y.z标签:Goose 稳定发布标签。该标签一旦打出即固定到同一提交
Goose 主发布周期
LTS (Long-Term Support) releases follow a separate maintenance cycle to provide extended support and stability.
Goose 主发布周期分为 3 个阶段:Mid-cycle、Pre-release、Feature freeze。这些阶段边界清晰,并会同步给团队,确保协同推进下一次发布。
阶段 1:Mid-Cycle
活跃 Goose 分支
mainvx.y-codename
说明
mid-cycle 是最常见阶段,约占周期 75% 时间。该阶段可视为日常开发期:下一次发布尚远,团队会合并各类功能与修复。在此期间,patch 版本(vx.y.<z+n>)可从 vx.y-codename 分支产出。补丁先合并到 vx.y-codename,再频繁回合并到 main,保持同步。
Goose PR 合并目标
- Bug-fixes for
vx.y.<z+n>patch releases are merged intovx.y-codename - Features and bug-fixes for
vx.<y+1>.0are merged intomain
阶段 2:Pre-Release
活跃分支
mainvx.y-codenamevx.<y+1>-codename
说明
pre-release 阶段用于准备即将到来的 vx.<y+1>.0 minor 发布。该阶段开始时会创建 vx.<y+1>-codename 分支。该分支用于产出下一个 minor 版本,以及后续 vx.<y+1>.<n> patch 版本。
Goose PR 合并目标
- Bug-fixes for
vx.y.<z+1>patch releases are merged intovx.y-codename - Features and bug-fixes for
vx.<y+1>.0are merged intovx.<y+1>-codename - Features for
vx.<y+2>.0are merged intovx.<y+2>-codename
阶段 3:Feature Freeze
活跃分支
mainvx.y-codenamevx.<y+1>-codename
说明
feature freeze 是最接近发布的阶段。在该阶段,vx.<y+1>-codename 不再接受功能合并,仅接收 bug 修复。目标是保障即将发布版本质量。此阶段会加强测试与基准验证,并通过禁止功能合并降低临近发布引入新问题的风险。
Goose PR 合并目标
- Bug-fixes for
vx.y.<z+1>are no longer allowed, should targetvx.<y+1>.0instead - Bug-fixes for
vx.<y+1>.0are merged intovx.<y+1>-codename - Features for
vx.<y+1>.0are no longer allowed, should targetvx.<y+2>.0instead - Features for
vx.<y+2>.0are merged intovx.<y+2>-codename
扩展主发布周期
多数 Goose 扩展与主仓库 goose/goose 完全分离,可采用自己的发布节奏。本节会按扩展类型说明各自发布周期。
在说明扩展发布周期前,先将扩展分成三类;同类扩展共享相近发布模型:
- In-tree extensions
- Unstable API extensions
- Stable API extensions
下面按复杂度递增依次说明三类扩展的发布周期。
In-Tree 扩展
对于 in-tree 扩展,发布周期最简单。由于代码位于 goose/goose 仓库,它们与 Goose 完全同频,版本与分支策略一致。某种意义上,它们更像 goose/goose 代码库中可延迟加载的模块。
Stable API 扩展
Stable API 扩展在 Goose 中是较新的方向,但未来预计会成为主流。它们基于稳定 C 扩展 API 构建,可与多个 Goose 版本保持二进制兼容,因此其发布周期可以/应当与 Goose 主发布周期解耦。
尽管 Stable API 扩展的发布流程仍在演进,但核心思路是:形成与 goose/goose 类似但独立的周期,每个扩展版本可面向 1 个或多个 Goose 版本。
Unstable API 扩展
Unstable API 扩展目前仍占多数。它们要么基于 C++ 扩展 API,要么基于不稳定 C 扩展 API。从发布周期视角看,这类扩展最复杂:每个扩展版本只面向单一 Goose 版本。这种 1:1 绑定使其发布周期与 Goose 主周期紧密耦合。虽然长期目标是迁移到稳定 API,但 unstable 扩展在较长时间内仍会存在,因此需要明确其生命周期。
按分支模型分类
首先将 unstable API 扩展按子类划分。与 Goose 类似,这些扩展也采用以 main 与 vx.y-codename 为核心的分支体系。我们按活跃分支数量定义三类:
- Single branch extensions have only the
mainactive branch - Two branch extensions have two active branches:
mainandvx.y-codename - Three branch extensions have three active branches:
main,vx.y-codename, andvx.<y+1>-codename
Goose 目标版本
每个 unstable API 扩展都应面向单一 Goose 版本。目标版本由 goose 子模块 与 MainDistributionPipeline 工作流中的目标版本共同决定。扩展具体面向哪个版本取决于发布阶段与分支,下面列出组合情况。
- Phase: Mid-cycle
- Type: Single branch
- Extension
main->Goosevx.y.zormain
- Extension
- Type: Two branch
- Extension
main->Goosevx.y.zormain - Extension
vx.y-codename->Goosevx.y.zorvx.y-codename
- Extension
- Type: Three branch: should not exist
- Type: Single branch
- Phase: Pre-release / Patch
- Type: Single branch
- Extension
main->Goosevx.y.zorvx.<y+1>-codename
- Extension
- Type: Two branch
- Extension
main->Goosevx.y.zorvx.<y+1>-codename - Extension
vx.y-codename->Goosevx.y.zorvx.y-codename
- Extension
- Type: Three branch
- Extension
main->Goosemain - Extension
vx.y-codename->Goosevx.y.zorvx.y-codename - Extension
vx.<y+1>-codename->Goosevx.<y+1>-codename
- Extension
- Type: Single branch
PR 应合并到哪里
unstable API 扩展的 PR 合并目标取决于两点:当前发布阶段和扩展类型。下面给出各组合规则。
- Phase: Mid-cycle
- Type: Single branch
- if Goose target:
vx.y.z:- PR for
vx.y.<z+1>intomain1 - PR for
vx.<y+1>.0merges intomain
- PR for
- if Goose target:
main:- PR for
vx.y.<z+1>are impossible - PR for
vx.<y+1>.0merges intomain
- PR for
- if Goose target:
- Type: Two branch
- PR for
vx.y.<z+1>merges intovx.y-codename - PR for
vx.<y+1>.0merges intomain
- PR for
- Type: Three branch
- PR for
vx.y.<z+1>merges intovx.y-codename - PR for
vx.<y+1>.0merges intovx.<y+1>-codename - PR for
vx.<y+2>.0merges intomain
- PR for
- Type: Single branch
- Phase: Pre-release / Patch
将发布哪个扩展版本?
每次 Goose 发布都应提供完整核心扩展集合。对 unstable API 扩展而言,这意味着需要重建二进制。核心扩展通常通过 goose/goose CI 构建。因此发布可用扩展列表记录在 extension config files 中。但该配置不一定始终最新。为确定某次发布应带哪个扩展版本,我们按发布类型(patch/minor)和扩展类型(single/multi branch)定义如下“权威来源”。
- Release type: Patch
- Extension type: Single branch
- Latest version: commit in config files
- Extension type: Multi branch
- Latest version: Extension
vx.y-codenamebranch
- Latest version: Extension
- Extension type: Single branch
- Release type: Minor
- Extension type: Single branch
- Latest version: Extension
mainbranch
- Latest version: Extension
- Extension type: Two branch
- Latest version: Extension
mainbranch
- Latest version: Extension
- Extension type: Three branch
- Latest version: Extension
vx.<y+1>-codenamebranch
- Latest version: Extension
- Extension type: Single branch
Single/Two/Three Branch 间切换
扩展分支类型之间的切换流程相对直接,建议按以下方式进行:
- Switch: Single branch
->Two branch- When: during any phase
- Reasons:
- When desire arises to merge features not eligible for
vx.y.<z+1>while also maintaining ability to do releases forvx.y.<z+n> - To be able to test with latest Goose main while maintaining ability to do releases for
vx.y.<z+n>(includingvx.y.zitself)
- When desire arises to merge features not eligible for
- Actions:
- Create branch
vx.y-codenamefrom a commit on main between HEAD ofmainand the commit in the Goosevx.y.zconfig file.
- Create branch
- Switch: Two branch
->Three branch- When: during Pre-release or Feature-freeze phase
- Reasons:
- Whenever a feature needs to be merged that is not eligible for merging into
vx.<y+1>.0.
- Whenever a feature needs to be merged that is not eligible for merging into
- Actions:
- Create
vx.<y+1>-codenamebranch from main
- Create
- Switch Three branch
->Two branch or Two branch->Single branch- When: part of transition from Feature Freeze
->Mid-cycle - Action: happens automatically (
vx.y-codenamebecomes inactive by definition)
- When: part of transition from Feature Freeze