夜天之书 #63 上游优先的故事 1 Spotless

前排提示,本文全文长 1.6w 字,由十个故事组成。出于微信公众号的展示特点,我将其切成若干个部分分开推送。如果想要单页读完全部内容,请点击阅读原文跳转网页,网页展示有目录,可以快速导航。

开源软件的用户在使用过程中遇到问题时,几乎总是先在自己的环境上打补丁绕过或快速修复问题。开源协同的语境下,开源软件以及维护开源软件的社群统称为该软件的上游,用户依赖上游软件的应用或基于上游软件复刻(fork)的版本统称为下游。上游优先(Upstream First),指的就是用户将下游发现的问题、做出的修改反馈到上游社群的策略。

网络上已经有不少文章讨论上游优先的定义、意义和通用的做法。例如,小马哥为极狐 GitLab 撰写了《Upstream First: 参与贡献开源项目的正确方式》[1]。不过,这些文章往往是站在社群、平台或布道师的层面做笼统的介绍。本文希望从一个开发者的角度出发,由几个具体的上游优先的故事,讨论开发者角度实践上游优先策略的动机和方法。

故事和经历

Spotless

第一个要讲的是我在 Spotless[2] 社群的参与经历。Spotless 是一个主要关注在 JVM 系语言的代码自动格式化软件,被 Apache Flink 等项目广泛采用。

我第一次给 Spotless 提交补丁是因为在一个个人项目当中同时使用 Java 17 和 Spotless 插件,遇到了 Java 17 严格约束 JDK 接口导致的 Spotless 插件启用 google-java-format 规则时不工作的情况。

起初,我按照 issue-834[3] 上的绕过方法解决了问题。但是一方面绕过方法不太舒服,需要用户感知和主动修改;另一方面,这个解法不向后兼容:如果一个项目想要同时支持 Java 8 和 Java 17 编译,该绕过方法会导致 Java 8 编译失败。

我遇到这个问题的时候,这个问题已经发生一年了。而且这种 Java 上游改内部接口导致下游爆炸的情况,一般很容易导致其他项目出问题。于是我尝试搜索相关问题,幸运地发现了 Kotlin 提供了解决问题根源的方法:

•KAPT does not fail with default settings on JDK 16+[4]

依样画葫芦就在 Spotless 上游把问题解了。

•Open com.sun.tools.javac modules on JDK 16+[5]•fix: get theUnsafe by reflection[6]

听起来简单,其实搜索到的代码片段只是提示了核心解法,减少了思考可行方案的时间。要把相关代码移植到另一个项目里,并且理解原项目的构建方式打包后测试,以及按照项目的惯例完成文档更新等等工作,最终让上游接受合并请求,就需要积极和上游维护者沟通,也需要发现和理解上游社群运行规则的方法和耐心。

好在 Spotless 的维护者 Ned Twigg 相当外向,很快进行代码评审并解释了代码以外需要做的工作,一周以内就完成了补丁合并。通过自动化发布的流程,补丁合并以后新版本就会自动发布,下游几乎能在合并当天就更新版本用上自己提交的补丁。

这里有个小插曲。虽然这个修复乍一看也可以在 google-java-format 上游做,但是我经历了 GCP 相关的一个 pull request 被挂数月的折磨以后,对 Google 项目实在没什么期待,所以选择在 Spotless 解决问题。事后发现这个解法是正确的,因为这样解能搞定 Spotless + google-java-format 1.7 的组合,而在 google-java-format 修大概率是不会为早期版本 pick 的。此外,Spotless 上的修复是模块化的,起初只是在 google-java-format 的路径上启用,随后发现了其他格式化规则也有类似的问题,只要简单地把修复模块在其他规则上启用就可以了。

一周以内上游合并发布以后,我在下游使用新版本的 Spotless 解决了之前的问题。然后,趁着热乎劲,我把之前搜索解法的时候搜到的其他有同样问题的项目,看着顺眼的就把我的修复版本提交给他们。今天我再去看原来的 issue 和提交的补丁,能够看到一系列下游项目引用我的工作修复他们的问题,我很开心。

然后,就在国庆假期前给 Flink 更新 Spotless 版本解决这个问题的时候,我又发现了另外一个问题,原先可以用过 skip 参数跳过某些 Maven 模块 Spotless 检查的功能在升级以后不管用了。

•[FLINK-29436][build] Upgrade spotless for running on JDK 17[7]

我的第一反应就是到上游搜索相似问题,发现 issue-1227[8] 也报告了这个问题。由于升级前的版本是好的,升级后的版本出了问题,加上我能定位到好的版本里 skip 参数起作用的相关代码是哪些,很快我就二分找到了引入问题的提交,并且在一个小时之内提交了修复。

•fix: maven plugin should identify skip config key[9]

这次轻车熟路,所有该办的我能办的事情,我都一次性搞完了。Ned Twigg 的反应还是很迅速,半小时内就反馈了 review 意见,我再求助其他开发者进行验证以后,当天 Ned Twigg 就合并了补丁并且自动发布了新版本。我接着在 Flink 提交的补丁上更新了依赖版本,第二天经过 review 以后 Flink 的补丁也合并了。而我本来还以为要到假期后才能搞定。

References

[1] 《Upstream First: 参与贡献开源项目的正确方式》: https://gitlab.cn/blog/2021/12/14/upstream-first/
[2] Spotless: https://github.com/diffplug/spotless
[3] issue-834: https://github.com/diffplug/spotless/issues/834
[4] KAPT does not fail with default settings on JDK 16+: https://github.com/JetBrains/kotlin/commit/52e45062cff913306872183ca38afe29fb7bfc79
[5] Open com.sun.tools.javac modules on JDK 16+: https://github.com/diffplug/spotless/pull/1224
[6] fix: get theUnsafe by reflection: https://github.com/diffplug/spotless/pull/1228
[7] [FLINK-29436][build] Upgrade spotless for running on JDK 17: https://github.com/apache/flink/pull/20911
[8] issue-1227: https://github.com/diffplug/spotless/issues/1227
[9] fix: maven plugin should identify skip config key: https://github.com/diffplug/spotless/pull/1353

猜你喜欢

转载自blog.csdn.net/weixin_44723515/article/details/127255632
63