首页
/ Flutter Engine What's New 生成器:一键产出两个版本间引擎变更摘要与 Diff 的技术实现解析

Flutter Engine What's New 生成器:一键产出两个版本间引擎变更摘要与 Diff 的技术实现解析

2026-09-05 10:52:25作者:郁楠烈Hubert

Flutter 单仓(monorepo)模式下,引擎源码位于 engine/src/flutter 下,每个季度版本之间会有上千个引擎提交。本文基于仓库内的 engine-whats-new Agent 技能,讲解如何对比两个 Flutter 发布版本在引擎目录下的全部变更,自动生成统一 diff 文件与按子系统分类的 "What's New" Markdown 摘要,并深入拆解其版本引用解析、提交归类规则与产物结构,读完你可以直接在本地复刻整个发布差异分析流程。

技能定位与触发边界

该技能定义于 SKILL.md,元信息声明了它的使用边界:

  • 技能名称engine-whats-new
  • 做什么:为 //engine/src/flutter 下两个发布版本(如 3.47 对比 3.44)之间的引擎变更,生成 "what's new" 发布摘要和 diff 文件;
  • 何时激活:仅当用户明确要求"生成引擎 what's new"、"对比引擎版本"或"产出引擎发布摘要"时;
  • 何时禁用:对于普通的提交查询、单文件历史或代码库搜索,除非明确要求生成引擎发布 diff/摘要,否则不使用该技能。

这种"何时用/何时不用"的显式声明,是 Flutter Agent Skills 目录所要求的良好实践之一——该 README 要求新技能面向 Flutter 贡献者设计、提供使用示例、遵循 agentskills 开放规范,并可用 dart_skills_lint 工具校验(命令见 skills README 的 "Validating Skills" 一节)。

输入识别:目标版本与基线版本

按技能工作流,第一步是从用户请求中提取两个输入:

输入 变量名 是否必填 示例
目标版本 <TARGET_RELEASE> 必填 3.473.47.0flutter-3.47-candidate.0
基线版本 <BASE_RELEASE> 可选 3.44;省略时脚本自动推算前一个季度版本

基线省略时的推算逻辑在 generate_engine_whats_new.dartdeducePreviousRelease 中实现:先剥离 flutter- 前缀和 -candidate.0 后缀,若主版本为 3 且次版本号可解析,则用 次版本号 − 3 得到上一季度版本(3.47 → 3.44,3.44 → 3.41)。其中有一个针对历史发布节奏的特殊修正:若结果次版本号为 28,则回退为 27。从源码结构看,这与 Flutter 历史上 3.28 前后发布节奏调整有关,属于对版本序列硬编码的补丁。

运行生成脚本

脚本为纯 Dart 实现,无第三方依赖(仅 dart:convertdart:io),在仓库根目录执行:

基本用法(自动推算基线)

dart .agents/skills/engine-whats-new/scripts/generate_engine_whats_new.dart --release 3.47

指定基线版本与自定义输出路径

dart .agents/skills/engine-whats-new/scripts/generate_engine_whats_new.dart \
  --release 3.47 --from 3.44 \
  --output-diff engine_diff_3.44_to_3.47.diff \
  --output-summary engine_whats_new_3.47.md

输出结构化 JSON 供程序消费

dart .agents/skills/engine-whats-new/scripts/generate_engine_whats_new.dart --release 3.47 --format json

完整参数说明

参数解析逻辑见 main 函数,与 scripts/README.md 保持一致:

参数 别名 默认值 说明
--release --to--target 必填 目标 Flutter 发布版本,如 3.47
--from --base 自动推算 基线版本;省略时按季度节奏推算(见上文 deducePreviousRelease
--engine-path engine/src/flutter 相对仓库根目录的引擎目录
--output-diff engine_diff_<base>_to_<target>.diff diff 文件输出路径
--output-summary engine_whats_new_<target>.md Markdown 摘要输出路径
--format markdown 标准输出格式:markdown / json / text
-h / --help 打印帮助信息(无参数运行时打印帮助并以退出码 1 结束)

另外脚本支持位置参数:第一个不以 - 开头的参数会被当作目标版本,等价于 --release

版本引用的解析策略

发布版本字符串(如 3.47)并不总能直接对应一个 git 引用,脚本的 tryResolveGitRef 按以下顺序逐一尝试 git rev-parse --verify

  1. 原样版本串,如 3.47
  2. 无点号的补全形式,如 73.7.0
  3. 主版本 3 的两段式版本补 .0,如 3.473.47.0
  4. release-candidate 分支(远程与本地):origin/flutter-3.47-candidate.0flutter-3.47-candidate.0,其中两段式输入还会尝试 origin/flutter-3.47-candidate.0 的缩写形式;
  5. v 前缀的 tag:v3.47v3.47.0

若以上引用均解析失败,则退化为 tag 模糊匹配:执行 git tag -l '*<version>*',优先返回精确等于 <version><version>.0 的 tag,否则取匹配列表的第一个。任一候选成功即返回该候选,全部失败则抛出 ArgumentError 终止分析。

以当前仓库实际验证:tag 3.47.0 可正常解析;而 flutter-3.47-candidate.0 在本地 clone 中不存在(git rev-parse 报 "Needed a single revision"),此时脚本会按候选列表继续尝试其他形式,体现了该回退链的必要性。

差异分析流程

analyzeEngineDiff 是核心入口,依次执行:

  1. 生成统一 diffgit diff <baseRef>..<targetRef> -- engine/src/flutter,结果完整写入 diff 文件;
  2. 统计短摘要git diff --shortstat 获取变更文件数、新增行、删除行,再用正则 (\d+)\s+files? changed 等分别提取三个数值;
  3. 枚举提交git log --pretty=format:%H%x09%h%x09%an%x09%ad%x09%s --date=short 以制表符分隔输出每个提交的完整哈希、短哈希、作者、日期与标题,并从中用 #(\d+) 正则提取 PR 编号;
  4. 逐条归类:按 categorizeCommit 的关键词规则将提交分入九大桶;
  5. 落盘摘要:由 generateMarkdownSummary 渲染 Markdown 并写入摘要文件。

在本地仓库实测 git diff --shortstat 3.44.9..3.47.0 -- engine/src/flutter 得到 1105 files changed, 47353 insertions(+), 18630 deletions(-),与脚本输出量级一致(技能文档示例中 3.44→3.47 报告约 354 commits、1179 files changed,数值差异源于基线 tag 的具体落点)。

提交分类体系

categorizeCommit 按"先匹配先得"的顺序用标题关键词判定分类,顺序本身即优先级(例如含 "Roll Skia" 的提交不会落入渲染类):

优先级 分类 命中关键词(小写匹配,节选)
1 🔄 Dependency Rolls Roll SkiaRoll Dart SDKRoll ICURoll HarfBuzzRoll ANGLE 前缀及小写变体
2 🚀 Impeller & Graphics Rendering impellerubersdfvulkanmetalopenglshaderdisplay_listrenderflow
3 🌐 Web Engine & Wasm [web]web_uiweb_sdkwasmskwasmcanvaskithtml
4 📱 Android Embedding [android]androidagpgradleembedding/engine
5 🍎 iOS & macOS Embeddings [ios][macos][darwin]xcodemetalview
6 🪟 Windows & Linux Desktop Embeddings [windows][linux]win32embedder
7 🔤 Text, Typography & Accessibility [a11y]semanticsaccessibilitytypographytxtfonttext inputautofill
8 🛠️ Build System, CI & Tooling [ci]ci:build.gntoolstestingheader_guardlicenseformat
9(兜底) ⚙️ Core Runtime & Shell 以上均未命中

这套关键词体系与引擎目录的实际结构相互印证:engine/src/flutter 顶层即包含 impeller(Impeller 渲染系统,下设 renderertypographershader_bundle 等子目录)、shell(运行核心)、txt(文本布局)、flowdisplay_listskwasmwasmweb_sdkvulkantestingtools 等目录,分类规则基本覆盖了引擎的主要子系统。

产物结构

工具在仓库根目录产出两份主要文件:

  1. Diff 文件engine_diff_<BASE>_to_<TARGET>.diff,路径中 / 会被替换为 _):两个版本间 //engine/src/flutter 的完整 unified git diff;
  2. 摘要文档engine_whats_new_<TARGET>.md):结构化 Markdown,包含
    • Overview & Statistics:diff 文件链接、引擎提交总数、变更文件数、新增行(+N)、删除行(-N);
    • 🌟 Subsystem Breakdown:按上述九大分类逐节列出提交,每行格式为 提交标题 (PR 链接 或 短哈希 by *作者*),其中标题含 #数字 的提交会生成指向 Flutter 仓库对应 PR 的链接,空分类会被跳过。

--format json 模式下,标准输出为 ReleaseAnalysis.toJson 的编码结果,字段包括 baseRelease/baseRef/targetRelease/targetRef/enginePath/diffPath/summaryPathstatstotalCommitsfilesChangedinsertionsdeletions)以及 categories(分类名到 CommitInfo 数组的映射,每条含 hashshortHashauthordatetitleprNumber),可直接被脚本或 Agent 二次消费。

文档中的两个典型用例

技能文档给出了完整的交互范式:

  • 用例一:用户说 "Generate what's new in the engine for Flutter 3.47"。Agent 识别目标版本 3.47,执行 dart .agents/skills/engine-whats-new/scripts/generate_engine_whats_new.dart --release 3.47,回报摘要统计(如 354 commits、1179 files changed),并给出生成的 engine_diff_3.44_to_3.47.diffengine_whats_new_3.47.md 两个产物。
  • 用例二:用户说 "Diff the engine changes between Flutter 3.41 and 3.44"。Agent 识别基线 3.41、目标 3.44,执行带 --from 3.41 --to 3.44 的命令,呈现引擎变更分解与 diff 文件。

使用前提与限制

  • 需要在包含完整 tag 历史的 Flutter 仓库根目录(或其子目录)运行——findRepoRoot 会从当前目录向上查找 .git 定位仓库根,找不到则退回当前目录;
  • 基线与目标版本必须都能被 tryResolveGitRef 解析,否则抛出 ArgumentError("Could not resolve git reference for ...");
  • 分类基于提交标题关键词,属于启发式规则,标题未含相关关键词的跨子系统提交可能落入兜底类 "⚙️ Core Runtime & Shell";
  • 前向推算基线仅对 3.x 序列有效,推算结果为空时必须显式指定 --from,脚本会报错退出。

小结

engine-whats-new 技能以一份无依赖的 Dart 脚本 generate_engine_whats_new.dart 串联了"版本引用解析 → git diff/log → 关键词归类 → Markdown/JSON 产物"的完整链路,把跨季度引擎变更审阅从手工翻日志简化为一条命令。配合 scripts/README.md 的参数说明,你可以将其用于发布前的引擎变更盘点,或作为 Agent 自动化发布摘要的标准工作流。

登录后查看全文
热门项目推荐
相关项目推荐