Flutter 仓库树卫生规范(Tree Hygiene):PR 落地、代码评审与回归处理的完整实践
【免费下载链接】flutterFlutter makes it easy and fast to build beautiful apps for mobile and beyond项目地址: https://gitcode.com/GitHub_Trending/flutter41/flutter
本文基于 Flutter 官方仓库的贡献文档 Tree-hygiene.md,系统讲解"树"(tree)健康状态的定义、PR 从提交到落地的完整流程、测试强制要求与豁免机制、代码评审的九项检查清单、AI 辅助贡献的约束规范,以及树损坏(tree breakage)、性能回归、跨仓库变更和破坏性变更(含 API 弃用规范)的处理策略,并结合仓库中的分析器插件源码说明弃用语法是如何被强制校验的。读完本文,你可以掌握在大型开源项目中保持主干持续绿色的工程方法论,并能在 Flutter 仓库中规范地完成一次从开分支到 revert 的全流程操作。
一、tl;dr:树卫生的四条铁律
原文档开篇即给出最核心的四条原则,这是整篇规范的浓缩:
- 回归必须先回滚(revert),问题以后再查(参见 Landing-Changes-With-Autosubmit.md)。把树恢复到绿色状态的优先级最高。
- 破坏性变更的定义:会破坏
flutter/tests仓库中测试的变更即为破坏性变更,且必须提供迁移指南(migration guide)。 - 评审响应预期:普通 patch 预期在两周内获得评审;如果是修复 P0 级 bug,则应在当天获得评审。若超出该时间窗口,应通过 Chat 渠道联系维护者。同时记住评审者是有工作与私人事务的真实的人。
- 并发 PR 数量限制:没有写权限的贡献者,每个仓库最多同时保持2 个打开的非草稿 PR(草稿 PR 不计入额度)。应优先合并或关闭已有 PR,再开新 PR。
二、什么是"树"(tree)及其状态展示
本文档中反复出现的 "tree" 一词,指flutter/flutter 仓库的健康状态(the health state of flutter/flutter repository)。树状态展示在三个地方:
- 构建看板(build dashboard);
- 每一个 PR 上(称为 "Tree Status" 检查)。这里有一个容易误解的点:PR 上 "tree-status" 检查失败,表示的是 main 分支本身有问题,而不是该 PR 本身的问题。该检查会在树维护者解决问题后自动通过,PR 作者无需采取任何行动;
- 社区的 tree-status 聊天频道。
三、提交代码到 Flutter 仓库的完整十步流程
这是原文档的主体操作脉络,完整继承如下:
- 在 GitHub 上 fork 仓库,并按照贡献指南配置开发环境。
- 确保有 issue 覆盖你要做的工作。如果没有,先提一个 bug/issue 描述你要解决的问题。issue 的价值在于:如果 PR 最终被回滚,可以重新打开 issue,不至于丢失"这项工作没有完整落地"的记录;如果某人做了一半 PR 后停止,issue 也为后来接手者提供了代码指向。
- 在 issue 上讨论设计方案(参见 Design-Documents.md)。可以使用 Google Doc 模板征求反馈,也可以发邮件列表或在 Chat 频道讨论。团队(尤其是相关 lead)的支持度越高,后续流程越顺畅。可以在 issue 上加
proposal标签,表示"这里有一个待讨论的设计"。 - 隐私影响评估:如果工作影响隐私面(例如修改 analytics 收集方式、崩溃日志等),应主动联系 Google 员工讨论变更,他们会拉入专注隐私问题的工程师给出反馈。
- 从
main(或尚未切换的仓库的master)拉出分支并实现变更,且必须保证有测试覆盖(见下文"测试"章节)。必须遵循 Style-guide-for-Flutter-repo.md 中描述的规范:文件不得有行尾空格。对引擎仓库,C、C++ 和 Objective-C 代码在提交前必须用clang-format格式化(使用buildtools/<OS>/clang/bin/clang-format --style=file -i)。 - 提交 PR(参见 Signing-commits.md)。再次强调并发限制:无写权限的贡献者每个公开 Flutter 仓库最多 2 个打开的非草稿 PR;草稿 PR 豁免;达到上限后应聚焦于合并或关闭已有 PR。所有提交给 Google 开源项目的代码都必须遵循 Google 的 Contributor License Agreement(CLA),即声明贡献是原创作品。这不禁止使用编码辅助工具,但提交的内容必须是贡献者本人的原创创作。
- 获取代码评审。如果你是团队成员,向你所触及领域的专家请求评审;否则等待系统分配评审者(见下文 "Who" 小节)。
- 确保 PR 通过所有 pre-commit 测试,并考虑在本地运行部分 post-commit 测试(如
dev/devicelab目录)。若有测试被破坏,尤其是customer_testing测试,参见下文"破坏性变更"章节。注意:luci-flutter测试并不是在检查你的 PR,它反映的是"此刻树本身是否通过测试"(包括 post-commit 测试)。当树或看板显示任何回归时,只允许能改善现状的修复进入。有两个 pre-commit 测试比较特殊,其失败并非由 PR 代码导致、也无法在 PR 内直接修复:tree-status:main 分支稳定性的状态指示器,阻塞树的问题解决后自动通过;Google Testing:在 Google 内部运行,不对外公开。若失败,应联系 Google 员工(例如 PR 评审者)查看内部测试并给出建议。
- 在一切变绿后落地:需要收到所影响代码 owner(或其授权委托人)的 LGTM,以及所有留下过评论的贡献者的 LGTM 后,如果你在 flutter-hackers GitHub 组内,给 PR 加上
autosubmit标签,bot 会在合适的时机落地该 patch;如果你不在该组,评审者会替你加标签。 - 在构建看板上监控 post-commit 测试,确保全部通过。若出任何问题,回滚你自己的 patch 并研究问题。原文档明确要求:"你应该争取成为回滚自己 patch 的那个人"——你会和团队中所有同样尝试回滚它的人竞速(revert 操作见下文)。
另可参见 What-should-I-work-on.md 了解选题建议。
四、测试要求:强制、豁免与评审机制
flutter/flutter 与 flutter/packages 仓库中的每一个变更都必须有测试;建议使用代码覆盖率工具检查新代码是否全部被测试覆盖(参见 Test-coverage-for-package-flutter.md)。
自动豁免的 PR 类型
以下 PR 自动豁免"必须有新测试"的要求:
- 仅删除代码(没有修改行或新增行),用于移除功能或死代码。
- 注意:为修复 bug 而删除代码仍然需要测试,豁免不适用;
- 仅影响注释(含文档);
- 仅影响
.github目录或.ci.yaml配置文件; - 仅影响
.md文件; - 由自动化 bot(rollers)生成的变更。
如果评审者认为 PR 应该有测试,那么无论上述豁免是否成立,都需要测试。
原文档特别提示:添加>git fetch upstream git checkout upstream/main -b name_of_your_branch flutter update-packages # Hack away. git commit -a -m "<your informative commit message>" git push origin name_of_your_branch
git push的输出中,GitHub 会提供提交 pull request 的链接。几条关键注意事项:
- 优先用
git fetch而非git pull:git pull常常丢失用于定义 flutter tool 发布版本的 tag,使用git fetch可以避免运行flutter update-packages时的版本不匹配;- 更新 PR 用 rebase 而非 merge:
git fetch upstream; git rebase upstream/main; git push origin your_branch_name。这样工具链才会认为你的 PR 是最新的(否则它可能针对你最初分叉时的测试来测试你的代码);- 小心对 PR 分支 force push,尤其是涉及 golden image 测试时(参见 Writing-a-golden-file-test-for-package-flutter.md 的 troubleshooting 部分);
- 提交信息必须详尽,说明问题是什么、解决方案是什么;避免在 commit message 中使用 GitHub @-mention——GitHub 会把 @ 变成通知,且别人在你自己的 fork 上 rebase 你的 commit 时也会触发通知,在如此规模的项目中干扰极大。需要 @ 某人时,请作为 PR 的单独评论;
- 必须完成 Google 的 Contributor License Agreement(CLA),在线签署仅需一分钟。
六、代码评审:目的、时机、对象与方法
每个 PR 在 check-in 之前都必须经过代码评审,包括滚依赖这样的"例行"操作。"获得评审"是指一位有 commit 权限的常规 Flutter 贡献者(贡献者权限细节见 Contributor-access.md)在 GitHub UI 中"approved"了该 PR,这被称为"拿到 LGTM"(looks good to me)。
如果你自己没有 commit 权限,则必须有第二位有 commit 权限的人也评审并批准你的 PR——这确保每一次提交都得到两位受信任贡献者的一致认可。
Why:评审的价值
- 捕获错误:即使最有经验的工程师也会犯只有评审才能发现的错误;
- 知识扩散:每一行代码都被两个人读过,你离开后别人仍能理解它;
- 保持诚实:知道有人要读你的代码,你会更少走捷径,更用心地写值得骄傲的代码;
- 暴露不同的思维方式:评审者大概率没有用和你相同的方式思考这个问题,可能带来全新视角和更优解。
When:何时请求评审
- 大 patch 要尽早请求评审,不必等到能 check-in 的时候;
- 不必犹豫地请多个人评审,也可以主动(unsolicited)评论别人的 PR(但 GitHub UI 中的 approve 动作应保留给有贡献者权限的人)。评审越多越好。
- 如果两周内无人评审你的 PR,可以在 Chat 频道(先问
#hackers)说明 patch 的作用并附上链接请求评审。Who:谁来评审
PR 的评审者按周分配,具体流程因团队而异,通常与 issue triage 结合进行。代码应由你所改动代码区域的所有者(tech lead)或其授权委托人评审;如果有任何其他人留下了评论,也要等他们的 LGTM 后再落地。两周无人评审的新贡献者可以去
#hackers-new频道求助。How:评审的执行要点
评审状态通过 GitHub 的 approval 机制管理:至少一位对代码很熟悉的有 commit 权限的贡献者必须在 GitHub UI 中批准 PR 后,PR 才能合并。评审者既要关注高层问题(方案是否合理、代码结构是否说得通),也要关注低层问题(可读性、是否符合 Flutter 风格指南)。
原文档给出了一份编号 0–9 的评审者检查清单,评审者被称为"最后一道防线"(the last line of defense):
- 作者签署了 CLA 吗?没有就请其签署,并且不要看代码;
- 退后一步:PR 要解决什么问题?是真实存在的问题吗?
- 还有什么其他解法?如何让它变得更好?
- 这是最好的 API 吗?参见风格指南的 philosophy 小节。寻找状态重复(state duplication)、同步慢操作、纠缠(complecting)、全局状态、过度特化的 API、API 悬崖(API cliffs)与 API 海洋(API oceans)、没有客户视角的 API 设计;
- 这是最好的实现吗?参见风格指南中"good coding patterns"一节。有没有 hack?是否引入了更多技术债?想想代码在哪些情况下可能坏掉;
- 可测吗?测了吗?所有代码都必须被测试。有 assert 吗?鼓励大量使用断言;
- 查找缩进错误和其他琐碎的格式问题;
- 新代码的 license 标注是否正确?
- 文档是否详尽且有用?寻找无用的文档、空洞的语句和"面包屑";
- 检查 API 文档和注释的语法质量,检查标识符命名是否符合约定。
只有在完全满意之后,才使用 GitHub 的 "Approval" 机制(一句 "LGTM" 评论是不够的)。如果感觉自己被消耗、被磨平,就把评审转给别人。
关于测试与责任:评审者不应在 patch 没有覆盖所有受影响代码的测试时给 LGTM(除非测试毫无意义)。评审一个 patch 意味着与该作者共同承担这个 patch 的责任——只有在你能自信地回答关于该代码的问题时,才给 LGTM。
一般原则:当 PR 处于"确定能改善整体代码健康度"的状态时,即使不完美也应倾向批准;评审过程中要给正向反馈,以对冲评审中批评流的冲击。评审者可以表达"这样更好"的意见,但如果不重要,请用类似"Shouldn't block this PR but: "的前缀让作者知道这只是可选打磨(这类意见应记录为带跟踪 issue 的 TODO 注释)。
非贡献者(无 commit 权限)的评审以评论形式欢迎,但请不要 approve/LGTM,因为这会误导 PR 作者以为其批准具有权威性而提前合并。
评论时的座右铭:
- 礼貌、感恩、优雅的专业度;
- 解释正在发生什么,解释为什么;
- 给出下一步,设定预期。
与其让 PR 悬而未决,不如关闭它(It's better to close a PR than to leave it in limbo)。
What:patch 被放弃时怎么办
有时贡献者无法完成落地工作。若 PR 有希望,团队可能关闭它,但在相关 issue 中提及,让其他感兴趣的人接手。此类 issue 会打
has partial patch标签。七、AI 辅助贡献指南
原文档设有专门章节约束使用 AI 工具准备的 PR,核心是对行为的要求,而不是对工具的限制:
- 必须审查所有 AI 生成的代码:在打开非草稿 PR 前,以及请求对 PR 任何更新重新评审前。你对提交代码符合 Flutter 项目标准负全责——未经修改的 AI 输出通常不符合这些标准;
- 必须理解并能讨论 PR 中的代码:非平凡 PR 在评审中需要讨论和迭代。如果你不理解代码,就无法有意义地回应评审反馈。经验表明,把评审反馈直接丢给 AI agent 然后不加批判地重新贴回其输出,不会带来建设性的评审;
- 必须核实 PR 描述和评审讨论中任何 AI 生成文本的准确性:AI 给错信息就是幻觉(hallucination);如果你把这段文本贴进 GitHub,就是在向评审者歪曲你的 PR。尤其不要因为在 AI 输出里声称已处理,就告诉评审者你已处理了他们的反馈——确认反馈被真正处理是你的责任。
评审者视角的红旗信号
由于团队时间有限,而团队外生成"看似合理代码"的能力近乎无限,评审者应对选择评审什么代码保持敏感。出现以下任一情况可考虑立即关闭 PR:
- PR 描述用 AI 生成输出完全替换了模板,且缺少至少一项明显清单内容(测试、issue 链接等)——一开始不遵循流程的人,不太可能在评审中理解对他们的期望;
- PR 描述与实际变更不符——贡献者没有同时审阅变更与描述到能发现这个程度,说明没有遵循 AI 贡献政策;
- PR 包含无关的 AI 生成文件,例如 agent 规划用的 .md 文件——没有审阅到足以发现并删除这些文件的程度,同样说明没有遵循政策。
关闭 PR 时和往常一样:解释原因并给出下一步。
指导原则:如果你在任何时候感觉自己在接收"未经过滤或仅最小过滤的 AI 输出",问自己:
- 如果这个 PR 不存在,我会选择花时间去修复这个问题吗?
- 我会选择用一个对每个提示都要花数小时/数天才响应的 AI agent 来修复它吗?
除非两个问题的答案都是"是",否则这个评审不是对你时间的好使用。这甚至适用于已经进行到多轮评审的情况——警惕沉没成本谬误(sunk cost fallacy)。
Philosophy:为什么需要 AI 政策
"代码应该自己说话,为什么在乎它怎么生成的?"——项目方总体上认同这一点,所以政策聚焦于行为。这些行为无论 AI 生成还是人类生成都是问题的,只是在 AI 参与时以高得多的频率出现,例如:
- 提交贡献者不理解的上百行代码的 PR 一直是问题,但在 AI agent 普及前很少见;
- 评审者要求修改、贡献者声称已改却实际没改——故意对评审者撒谎极罕见,但不加批判地重复 AI agent 幻觉却不幸地常见;
- 无视流程的 PR 一直是问题,因为标准化 PR 流程是控制评审量的关键。花了数小时/数天的贡献者,比几分钟生成 PR 的贡献者更花时间去学习和遵循流程,以保护自己的投入不被浪费。
八、落地 patch 与树损坏(Tree Breakage)
拿到 LGTM 之后:没有 commit 权限时,等待项目维护者替你提交;有权限时,给 PR 加
autosubmit标签,bot 会替你落地。任何一次 check-in 如果导致 main 分支(有时称 master)在任一 flutter 仓库出现回归,就回滚该 check-in——即使它不是你提交的。不要尝试"向前修复"(forward-fix)post-submit 测试失败。原文档宽慰道:"犯错不丢人!Revert 随时发生,是工程的正常部分。"
回滚一个 PR 的操作很简单:给它加上
revert标签(更多细节见 Landing-Changes-With-Autosubmit.md)。避免 'Revert "Revert "Revert "Revert "Fix foo""""' 式提交信息
提交信息中最多只允许出现一个 "Revert",否则没有人能判断这次落地实际做了什么:是回到之前的状态?是加入新代码?还是那个之前引起回归、这次修好了的争议特性?只有当你确实在把大家带回到一个已知的良好状态时,才使用 "Revert"。同时避免使用 "Reland":当之后要 revert 那个 revert 时,直接用原始提交信息(可补充后续收集到的信息)重新落地 PR,并附上原始 PR 与 revert PR 的链接,让大家能顺藤摸瓜。
九、性能回归的处理
每次 check-in 后应监控性能看板。看到回归(你的 commit 之后任意图表数值上升)时:
- 在 PR 上评论确认该回归;
- 如果回归是预期中且是有利的权衡(例如磁盘占用略增换取速度大幅提升),对相关基准进行 rebaseline(登录后点每张图右上角的放大镜,再点自动 rebaseline 并提交);
- 如果回归不预期且可能是你 PR 的问题,revert 你的 PR 并调查;
- 如果回归不预期且相当严重,revert 你的 PR 并调查;
- 如果回归不预期、不严重且确定不是你 PR 的问题(例如你只改了注释而分析器变慢),提一个打
regression、performance、P0标签的 bug,自己或委托他人调查。调查应被视为高优先级,你有责任在几天内确保原因被理解。Flutter 将所有意外的性能回归视为 P0,直到它被控制(即已知原因,且要么修复在进行中,要么已判定是可接受的权衡)。性能回归只要被及时处理就不是问题。
由 auto-roller 提交引起的性能回归
回滚一个普通提交是默认行为,但回滚一个 auto-roller 提交(如 engine-roller)会引起一些复杂情况:
- auto-roller 提交通常包含源仓库的多个提交(例如 skia-roller 包含 skia 的多个提交),且可以递归叠加(某些 roller 包含另一个 roller 的提交)。因此一个 roller 提交实际可能包含大量叶子级提交,很难定位到底是哪个叶子提交引起了回归;
- auto-roller 会尽快再次滚入,这会把 Flutter 侧 revert 掉的变更重新滚回来。要维持 revert 有效,要么(1)暂停 auto-roller,要么(2)在源仓库中 revert 那个叶子提交;
- 如果 auto-roller 暂停太久(比如一天),源仓库会积累很多提交,使下一次滚入非常难管:来自下一次滚入的构建失败或新性能回归很难 triage,因为那次滚入包含暂停期间的所有提交。
因此,revert roller 提交或暂停 auto-roller 并不是引起性能回归时的默认动作。默认动作是:立即提一个打
performance、regression、P0标签的 issue,开始调查是哪个叶子提交引起回归。定位后,判断是否预期权衡:是则去掉P0标签并寻找缓解手段;否则在源仓库中 revert 那个叶子提交,让 auto-roller 把该 revert 滚入 Flutter,滚入后关闭 issue。十、跨仓库(相互依赖)变更
如果一个特性需要同时修改框架仓库和引擎仓库,你需要开两个独立的 PR。此时框架 PR 的 CI 可能因依赖尚未进入引擎 main 分支的引擎代码而失败。这种情况下,先在引擎仓库落地变更,等待它们滚入框架 main 分支,然后 rebase 你的框架 PR。
十一、破坏性变更(Breaking Changes)
原则上,Flutter 希望避免任何"迫使使用 Flutter 的开发者改代码才能升级"的变更(参见官方兼容性政策)。但有时为了更大的善是必要的:我们希望 API 直观;如果保持向后兼容需要把一个 API 变成"若非被迫绝不会这样设计"的东西,那么不如干脆破坏它并把它做好。
第 1 步:判断你的变更是否是破坏性变更
实现你想要的变更,然后在不先修改测试的前提下用现有测试跑你的新代码。凡破坏(即要求修改)一个或多个 contributed tests 的变更,即为破坏性变更。
"contributed tests" 包括:
flutter/flutterPR 上customer_testing分片中的测试;- 我们获准运行但不公开的其他测试套件(例如 Google 允许我们在每次提交上运行数万个内部专有测试,参见 Understanding-Google-Testing.md)。
此政策没有豁免,因为这些测试在 CI 中运行,破坏它们就会关树。
即使这些测试都通过,只要能想象出开发者可能受到负面影响的合理场景,出于礼貌,变更落地后工程师应通过邮件列表、Chat 的
#announcements频道通告,并给相关 issue 打c: API break标签使其进入 release notes——但这不被视为破坏性变更(例如:即使没有 contributed test 实际失败,我们自己的测试受到显著影响时也应如此通告)。第 2 步:评估破坏性变更
如果你的变更算破坏性变更,认真考虑它是否真的必要且有收益。考虑写一份设计文档,与代码评审者讨论,并在 Chat 上提出。
第 3 步:准备你的变更
如果认定变更价值足够,调整 PR 使其以opt-in(选择性开启)方式引入新功能、API、行为变化,从而避免立即破坏。
例如:不要直接用一个 widget 替换另一个,而是引入新 widget 并引导用户弃用旧的;不要直接改变某参数的处理顺序,而是提供一个 flag 来选择顺序。
当以临时 opt-in 方式改变一个 API 的语义时,需要三阶段变更(加入新 API 和 opt-in → 移除旧 API → 移除 opt-in)。
尽量避免四阶段弃用(加入新 API 并起临时名、弃用旧 API → 移除旧 API → 把新 API 改名回旧名并弃用临时名 → 移除临时名),因为它带来大量 churn 并会激怒开发者。
变更和变更文档要分阶段提交。通常是两个或更多 PR,外加修复第 1 步中被破坏测试的 PR,以及作为 Website 仓库 PR 的迁移指南。如果可能,包含 flutter fix 以帮助用户迁移,并在迁移指南中说明该变更是否被 flutter fix 支持(编写 fix 参见 Data-driven-Fixes.md)。
使用官方破坏性变更迁移指南模板创建描述该变更的迁移指南(遵循模板中注释里的所有说明)。此时不要落地迁移指南——你还需要在最后一步落地前更新它。
第 4 步:落地你的变更
准备好、收到反馈、迭代了设计与迁移指南之后,落地初始变更并开始迁移客户。此时仍不要落地迁移指南。等所有客户迁移完成后,落地最终变更(多阶段推出时这里可能有多轮迭代)。此过程中每个单独的 PR 都不破坏任何测试,因此不应阻塞任何 autoroller。
第 5 步:记录变更,包括清晰的迁移代码文档
一切落地之后:
- 根据你迁移所有人的实际经验更新迁移指南;
- 更新指南上的时间线,并推送到 flutter.dev 网站(记得同时更新该目录的 index);
- 把副本发到通告邮件列表;
- 在 Chat 的
#announcements频道通知;- 给相关 issue 加
c: API break标签,使其出现在即将发布的 Release notes 中。弃用(Deprecations)规范
旧 API 可以在此流程中被标记为弃用。弃用不是逃避破坏性变更的手段——应把弃用 API 等同于移除 API 来考虑,因为部分客户(包括我们自己)把使用弃用 API 视为禁忌(会触发构建失败)。
弃用注释必须匹配如下模式:
@Deprecated( 'Call prepareFrame followed by owner.requestVisualUpdate() instead. ' 'This will enable an improvement to performance in a future version of Flutter. ' 'This feature was deprecated after v2.9.0-0.1.pre.' )即三段式:
@Deprecated( '[迁移方法描述] ' '[为什么破坏该 API 的简短动机] ' 'This feature was deprecated after v[弃用时的 beta 版本].' )使用这种标准格式可以让我们写脚本检测并移除所有弃用 API。仓库中确实有一个测试验证该语法——具体实现就在分析器插件 deprecation_syntax.dart 中。从源码看,该规则(
DeprecationSyntax)以 ERROR 级别检查:
- 弃用消息必须是相邻字符串拼接(AdjacentStrings)形式;
- 最后一个字符串字面量必须匹配正则
This feature was deprecated after v(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)(?<build>-\d+\.\d+\.pre)?\.$,即版本号必须以v开头并以句点结尾;- 版本号必须是beta 分支版本:规则特别处理了
3.1.0这个特例(可不带 build 后缀),其余满足major > 1或major == 1 且 minor >= 20的版本号必须带-\d+\.\d+.pre的 build 后缀;- 描述部分每条字符串必须用单引号、以大写字母开头、以
.、?或!结尾;- 不符合时可通过
// flutter_ignore: deprecation_syntax或带 issue 链接的 legacy 注释豁免。该规则的测试用例 deprecation.dart 覆盖了各种合法与非法场景(错误的版本号、缺 version 行、双引号字符串、大小写错误等),并由 deprecation_syntax_test.dart 驱动验证。最新 beta 版本号可查 flutter.dev 的安装归档页。
在框架中加入弃用通知时,应随变更附带一个 flutter fix,帮助用户尽可能容易地迁移;如果无法为新 API 编写 fix,请向 dart-lang/sdk 提 issue 并在变更中链接。
一个实战陷阱:弃用某个特性时,你自己默认不会被通知 Flutter 代码自身使用该弃用特性的位置——因为根 analysis_options_common.yaml 中有这样一段配置:
analyzer: errors: # allow deprecated members (we do this because otherwise we have to annotate # every member in every test, assert, etc, when we or the Dart SDK deprecates # something) deprecated_member_use: ignore deprecated_member_use_from_same_package: ignore文档给出的找法是:把声明改名,看编译器在哪里抱怨(不能直接注释掉 "ignore",因为它还压着成百上千个其他警告……)。
最后,框架中目前不计划移除弃用 API(历史上曾按固定时间移除,现在没有在实践中执行)。若将来恢复移除,会跨多个渠道(通告邮件列表、Discord 等,见 Chat.md)提前宣布。
十二、跳过的测试(Skipped Tests)
测试可以用
test()、group()和testWidgets()的skip参数跳过,但应保持最少,且只允许以下两个理由:理由一:flaky 测试的临时跳过——为了在修复开发期间保持树绿色。必须提一个跟踪 issue 以确保后续有人移除 skip,该 issue 打
skip-test标签,并在参数同一行的注释中包含链接:skip: true, // https://github.com/flutter/flutter/issues/XXXXX理由二:设计上在特定条件下无意义的测试——例如只测试某个特定平台/环境可用特性的测试。在
skip参数同行加[intended]标记和简短说明:skip: isBrowser, // [intended] There are no default transitions to test on the web.仓库的 bot 代码本身大量使用这种约定,例如 check_examples_cross_imports_test.dart 中就有
skip: hasNoCrossImports, // [intended]: Nothing to log if there are no known imports这样的用例。如果分析器脚本看到一个
skip,而它的注释既没有 issue 链接也没有[intended]标记,就会报错并使该检查失败。小结
Tree-hygiene 规范体现的核心工程哲学是:主干绿色压倒一切(回归先 revert 再调查)、双信任人评审机制(两位有 commit 权限者共同批准)、测试是默认义务(豁免是例外且受审计)、破坏必须分阶段并全程留痕(opt-in 三阶段 + 迁移指南 + 通告),以及对自动化流程(auto-roller、autosubmit bot、deprecation 语法检查插件)的敬畏与适配。上述每一条都能在仓库中找到对应的制度落点:从 analysis_options_common.yaml 的分析器配置,到 dev/flutter_analyzer_plugin 中强制弃用语法的插件规则,再到
dev/bots下的各类检查脚本——规范文本与代码实现互为印证,共同维持着这个大型仓库的持续健康。【免费下载链接】flutterFlutter makes it easy and fast to build beautiful apps for mobile and beyond
项目地址: https://gitcode.com/GitHub_Trending/flutter41/flutter
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考