本指南记录了为 Apache Spark 做出各种类型贡献的最佳方式,包括提交代码更改之前需要做的事情。

贡献 Spark 不仅仅意味着编写代码。在邮件列表中帮助新用户、测试版本以及改进文档也同样受欢迎。事实上,提出重要的代码更改通常需要首先通过以其他方式提供帮助来获得社区内的经验和信誉。这也是成为有效贡献者的指南。

因此,本指南按照新的贡献者打算长期参与的顺序组织贡献。积累一些帮助他人的记录,而不仅仅是打开拉取请求。

通过帮助其他用户做出贡献

为 Spark 做出贡献的一个好方法是在 user@spark.apache.org 邮件列表或 StackOverflow 上回答用户的问题。总是有许多新的 Spark 用户;花几分钟时间来帮助回答问题是一项非常有价值的社区服务。

贡献者应订阅此列表并关注它,以便及时了解 Spark 中发生的事情。回答问题是一种极好的、可见的方式来帮助社区,同时也展示了您的专业知识。

请参阅邮件列表指南,了解有关如何有效地参与邮件列表上的讨论以及 StackOverflow 等论坛的指导。

通过测试版本做出贡献

Spark 的发布流程以社区为导向,社区成员可以在 dev@spark.apache.org 邮件列表上对新版本进行投票。邀请 Spark 用户订阅此列表以接收公告,并在较新版本上测试其工作负载,并提供有关在较新版本中发现的任何性能或正确性问题的反馈。

通过审查更改做出贡献

对 Spark 源代码的更改通过 GitHub 拉取请求(稍后描述)提出、审查和提交。任何人都可以查看和评论此处的主动更改。审查他人的更改是学习更改流程如何运作的好方法,并可以了解代码各个部分的活动。您可以通过审查更改并提出问题或指出问题(例如简单的拼写错误或小的样式问题)来提供帮助。另请参阅 https://spark-prs.appspot.com/,以方便查看和筛选打开的 PR。

贡献文档更改

要提议更改发布文档(即,出现在 https://spark.apache.org/docs/ 下的文档),请编辑 Spark docs/ 目录中的 Markdown 源文件,其 README 文件显示了如何在本地构建文档以测试您的更改。提议文档更改的过程与下面提议代码更改的过程相同。

要提议更改其余文档(即,出现在 https://spark.apache.org/docs/ 下的文档),同样,请编辑 spark-website 存储库中的 Markdown 并打开一个拉取请求。

将用户库贡献给 Spark

正如 Java 和 Scala 应用程序可以访问大量的库和实用程序一样,这些库和实用程序都不是 Java 或 Scala 本身的一部分,Spark 旨在支持丰富的库生态系统。许多新的有用实用程序或功能都属于 Spark 之外,而不是核心部分。例如:语言支持可能必须是核心 Spark 的一部分,但是,有用的机器学习算法可以很乐意地存在于 MLlib 之外。

为此,大型且独立的新功能通常会被拒绝包含在 Spark 本身中,但是,可以并且应该作为单独的项目和存储库托管,并包含在 spark-packages.org 集合中。

贡献错误报告

理想情况下,错误报告应附有建议的代码更改以修复该错误。这并非总是可能的,因为发现错误的人可能没有修复错误的经验。可以通过创建 JIRA 来报告错误,而无需创建拉取请求(见下文)。

但是,只有当错误报告包含足够的信息来理解、隔离和理想地重现该错误时,错误报告才有用。仅仅遇到错误并不意味着应该报告错误;如下所述,首先搜索 JIRA 并在 Spark 用户/开发邮件列表中搜索和查询。不可重现的错误或简单的错误报告可能会被关闭。

如果错误报告包含有关错误的引入方式以及哪个提交引入的描述,这将非常有帮助,以便审阅者可以轻松理解该错误。当拉取请求合并时,它还有助于提交者确定应将错误修复向后移植到多远。修复错误的拉取请求应将问题缩小到根本原因。

性能下降也是一种错误。修复性能下降的拉取请求必须提供一个基准来证明问题确实已修复。

请注意,数据正确性/数据丢失错误非常严重。确保相应的错误报告 JIRA 工单标记为 correctnessdata-loss。如果错误报告没有得到足够的关注,请发送电子邮件至 dev@spark.apache.org,以引起更多关注。

也可以提出新功能。除非附有详细信息(例如设计文档和/或代码更改),否则这些通常没有帮助。大型的新贡献应首先考虑 spark-packages.org(参见上文),或者首先在邮件列表中进行讨论。功能请求可能会被拒绝,或者在长时间不活动后被关闭。

贡献 JIRA 维护

鉴于 Apache Spark JIRA 中提出的问题数量之多,不可避免地会出现一些重复的问题,或者变得过时并最终以其他方式修复,或者无法重现,或者可以从更多细节中受益等等。帮助识别这些问题并解决它们(无论是通过推进讨论还是甚至解决 JIRA)非常有用。大多数贡献者可以直接解决 JIRA。在确定您非常有信心应该解决该问题时,请使用判断力,尽管可以轻松撤消更改。如有疑问,只需在 JIRA 上发表评论。

解决 JIRA 时,请遵守一些有用的约定

  • 如果存在您可以指向的已解决问题的更改,则解决为已修复
    • 设置修复版本,当且仅当解决方案为已修复时
    • 将受让人设置为对解决方案贡献最大的人,通常是打开 PR 以解决该问题的人。
    • 如果有多个人贡献,请优先分配给更“初级”的非提交者贡献者
  • 对于无法按照报告在 master 上重现的问题,解决为无法重现
    • 如果很明显其他先前的拉取请求解决了该问题,则修复也是合理的。链接到它。
  • 如果问题与另一个问题相同或属于其子集,则解决为重复
    • 确保链接到它重复的 JIRA
    • 首选将活动或讨论较少的问题解决为重复问题
  • 如果问题看起来明显过时,并且适用于自打开以来已发生根本变化的 issue 或组件,则解决为不是问题
  • 如果问题没有意义 – 例如,不可操作,非 Spark 问题,则解决为无效
  • 如果这是一个连贯的问题,但有明确的迹象表明没有支持或兴趣对其采取行动,则解决为不会修复
  • 如果伞只是不对应于其自身的可操作更改的容器问题,则通常标记为完成

准备贡献代码更改

选择要贡献的内容

Spark 是一个异常繁忙的项目,平均每隔几个小时就会有一个新的 JIRA 或拉取请求。审查可能需要提交者花费数小时或数天的时间。如果贡献者专注于有用、清晰、易于评估且已通过基本检查的更改,那么每个人都会受益。

有时,贡献者已经想到了特定的新更改或错误。如果正在寻找想法,请查阅 JIRA 中的入门任务列表,或咨询 user@spark.apache.org 邮件列表。

在继续之前,贡献者应评估建议的更改是否可能相关、新颖且可操作

  • 是否清楚代码必须更改?仅当已确定明确的问题或更改时,提出 JIRA 和拉取请求才是合适的。如果只是在使用 Spark 时遇到问题,请首先使用邮件列表,而不是考虑提交 JIRA 或提出更改。如有疑问,请首先通过电子邮件 user@spark.apache.org 询问可能的更改
  • 搜索 user@spark.apache.orgdev@spark.apache.org 邮件列表 档案以进行相关讨论。通常,问题已被讨论过,解决方案不需要代码更改,或者记录了哪些类型的更改将不被接受为解决方案。
  • 在 JIRA 中搜索现有问题:https://issues.apache.org/jira/browse/SPARK
  • 在右上角的搜索框中键入 spark [搜索词]。如果存在逻辑上类似的问题,请首先对现有 JIRA 和拉取请求进行讨论,而不是创建一个新的。
  • 更改的范围是否与贡献者的经验水平相匹配?任何人都有资格提出拼写错误修复建议,但重构核心调度逻辑需要对 Spark 有更多的了解。某些更改需要首先积累经验(参见上文)。

值得再次强调的是,对 Spark 核心或者像 SQL 和 Catalyst 这样高度复杂和重要的模块进行更改,更难以正确完成。它们会受到更严格的审查,并且审核标准会高于对不太关键的代码的更改。

MLlib 特定的贡献指南

虽然丰富的算法集是 MLLib 的一个重要目标,但扩展项目需要将可维护性、一致性和代码质量放在首位。新的算法应该:

  • 广为人知
  • 被使用和接受(学术引用和具体的用例可以帮助证明这一点)
  • 高度可扩展
  • 文档齐全
  • 具有与 MLLib 中完成相同事情的其他算法一致的 API
  • 对开发人员的支持有合理的期望。
  • 在公共类、方法和变量上具有 @Since 注释。

错误消息指南

Spark 中抛出的异常应与标准化和可操作的错误消息相关联。

错误消息应回答以下问题

  • 什么 是问题所在?
  • 为什么 会发生这个问题?
  • 如何 解决这个问题?

编写错误消息时,你应该

  • 使用主动语态
  • 避免基于时间的陈述,例如承诺未来的支持
  • 使用现在时来描述错误并提供建议
  • 如果解决方案不明确,请提供具体示例
  • 避免听起来是指责、评判或侮辱性的
  • 直接
  • 不要在面向用户的错误中使用编程术语

有关更多详细信息,请参见错误消息指南

行为变更

行为变更是新版本中通过公共 API 可以观察到的用户可见的功能变更。“用户”一词在这里不仅指编写查询和/或开发 Spark 插件的人,还指部署和/或管理 Spark 集群的人。新的特性和缺陷修复,例如修正查询结果或模式以及使先前返回错误结果的不支持的查询失败,都被认为是行为变更。但是,性能改进、代码重构以及对未发布 API/特性的更改则不是。

每个人都会犯错,包括 Spark 开发人员。我们将继续修复 Spark 中出现的缺陷。但是,重要的是要沟通这些行为变更,以便 Spark 用户可以为版本升级做好准备。如果 PR 引入了行为变更,则应在 PR 描述中明确提及。如果行为变更可能需要额外的用户操作,则应在迁移指南中突出显示(SQL 组件的 docs/sql-migration-guide.md 以及其他组件的类似文件)。如果可能,请提供恢复先前行为的选项,并在错误消息中提及这些选项。一些例子包括:

  • 更改查询结果的缺陷修复。用户可能需要回填以更正现有数据,并且必须被告知这些正确性修复。
  • 更改查询模式的缺陷修复。用户可能需要更新其数据管道中表的模式,并且必须被告知这些更改。
  • 删除或重命名 Spark 配置。
  • 重命名错误类或条件。
  • 对公共 Python/SQL/Scala/Java/R API(包括开发人员 API)的任何非增量式更改,例如重命名函数、删除参数、添加参数、重命名参数或更改参数默认值。通常应避免这些更改,或者如果必要,应以二进制兼容的方式进行,即弃用旧函数并引入新函数来代替。
  • 对部署和管理 Spark 的方式的任何非增量式更改:重命名部署脚本中的参数名称、更新 REST API、更改加载配置文件的方法等。

此列表并非详尽无遗。如果审查 PR 的人认为该更改有风险并可能在升级期间中断用户,则可以要求 PR 作者将其添加到迁移指南中。

代码审查标准

在考虑如何贡献代码之前,了解如何审查代码以及为什么可能拒绝更改是有用的。请参阅 Google 工程实践文档中代码审查者的详细指南。简而言之,具有许多或大的积极影响,以及很少的消极影响或风险的更改,更有可能被合并,并且合并速度更快。风险较高且价值较低的更改不太可能被合并,并且可能会被直接拒绝,而不是进行多次审查。

积极方面

  • 修复了现有功能中的错误的根本原因
  • 添加了大量用户需要的功能或修复了问题
  • 简单,有针对性
  • 保持或提高 Python、Java、Scala 的一致性
  • 易于测试;有测试
  • 降低复杂性和代码行数
  • 更改已经过讨论,并且提交者已知

消极方面,风险

  • 仅修补了错误的症状
  • 引入了复杂的新功能,尤其是一个需要支持的 API
  • 增加了仅对小众用例有帮助的复杂性
  • 添加了不需要在 Spark 中维护的用户空间功能,但可以在外部托管并由 spark-packages.org 索引
  • 更改了公共 API 或语义(很少允许)
  • 添加了大型依赖项
  • 更改了现有依赖项的版本
  • 添加了大量代码
  • 在一个“大爆炸”更改中进行了大量修改

贡献代码更改

在提出代码更改之前,请先查看前面的部分。本节介绍如何执行此操作。

当您贡献代码时,您确认该贡献是您的原创作品,并且您根据项目的开源许可证将该作品许可给项目。无论您是否明确声明这一点,通过 pull request、电子邮件或其他方式提交任何受版权保护的材料,您都同意根据项目的开源许可证许可该材料,并保证您拥有这样做的法律授权。

克隆 Apache Spark 源代码

如果您有兴趣使用最新的开发中代码或为 Apache Spark 开发做出贡献,您可以从 Git 检出 master 分支

# Master development branch
git clone git://github.com/apache/spark.git

下载 Spark 后,您可以在文档页面上找到有关安装和构建它的说明。

JIRA

通常,Spark 使用 JIRA 来跟踪逻辑问题,包括错误和改进,并使用 GitHub pull request 来管理特定代码更改的审查和合并。也就是说,JIRA 用于描述应该修复或更改的内容以及高级方法,而 pull request 用于描述如何在项目的源代码中实现该更改。例如,主要的架构决策将在 JIRA 中讨论。

  1. 查找与更改相关的现有 Spark JIRA。
    1. 如果创建更改是为了解决 JIRA 中的现有问题,请不要创建新的 JIRA;而是添加到现有的讨论和工作中
    2. 查找从 JIRA 链接的现有 pull request,以了解是否有人已经在处理该 JIRA
  2. 如果更改是新的,那么它通常需要一个新的 JIRA。但是,对于微不足道的更改,其中应该更改的内容与应该如何更改的方式几乎相同,则不需要 JIRA。示例:修复 Foo scaladoc 中的错别字
  3. 如果需要,创建一个新的 JIRA
    1. 提供一个描述性的标题。“更新 Web UI”或“调度程序中的问题”是不够的。“Kafka Streaming 支持无法处理 YARN 集群模式下的空队列”是好的。
    2. 编写详细的描述。对于错误报告,理想情况下应包括问题的简短重现。对于新功能,它可能包括设计文档。
    3. 设置必填字段
      1. 问题类型。通常,Bug、Improvement 和 New Feature 是 Spark 中唯一使用的类型。
      2. 优先级。设置为 Major 或更低;更高的优先级通常保留给提交者设置。主要的例外是正确性或数据丢失问题,可以将它们标记为 Blockers。 JIRA 倾向于不幸地将其“大小”和“重要性”混淆在其 Priority 字段值中。它们的含义大致是:
        1. Blocker:如果没有此更改,则发布毫无意义,因为该版本对很大一部分用户来说将无法使用。正确性和数据丢失问题应被视为其目标版本的 Blockers。
        2. Critical:很大一部分用户没有此功能,并且/或者解决方法很困难
        3. Major:一小部分用户没有此功能,并且有解决方法
        4. Minor:一个小众用例缺少一些支持,但这不会影响使用或可以轻松解决
        5. Trivial:一个锦上添花的更改,否则不太可能在实践中出现任何问题
      3. 组件
      4. 影响版本。对于 Bug,分配至少一个已知表现出问题或需要更改的版本
      5. 标签。未广泛使用,以下情况除外:
        • correctness: 一个正确性问题
        • data-loss: 一个数据丢失问题
        • release-notes: 更改的效果需要在发行说明中提及。 JIRA 或 pull request 应包括适合包含在发行说明中的详细信息——请参见下面的“Docs Text”。
        • starter: 适合新贡献者的小型、简单的更改
      6. 文档文本:对于需要在发行说明中包含条目的问题,这应该包含发行经理应包含在发行说明中的信息。这应该包括受影响的行为的简短摘要,以及有关行为更改的详细信息。可以在打开 JIRA 时临时填写,但在问题解决后可能需要使用最终详细信息进行更新。
    4. 不要设置以下字段
      1. 修复版本。这仅由提交者在解决时分配。
      2. 目标版本。这由提交者分配,以指示已接受 PR 以供目标版本可能修复。
    5. 不要包含补丁文件;pull request 用于提出实际更改。
  4. 如果更改是一个很大的更改,请考虑在进行更改之前,先在 dev@spark.apache.org 上邀请讨论该问题。

Pull request

在 Apache Spark 中创建 pull request 之前,重要的是检查测试是否可以在您的分支上通过,因为我们的 GitHub Actions 工作流程会自动为您的 pull request/后续提交运行测试,并且每次运行都会加重 Apache Spark 存储库中 GitHub Actions 有限资源的负担。以下步骤将引导您完成该过程。

  1. 如果您尚未这样做,请Fork位于 https://github.com/apache/spark 的 GitHub 存储库
  2. 转到您 Fork 的存储库上的“Actions”选项卡,并启用“Build and test”和“Report test results”工作流程
  3. 克隆您的 Fork 并创建一个新分支
  4. 考虑是否需要添加或更新文档或测试作为更改的一部分,并根据需要添加它们。
    1. 添加测试时,请确保测试具有自我描述性。
    2. 此外,当你的 pull request 旨在修复特定问题时,你应该考虑在测试中编写 JIRA ID。 实际上,通常在 JIRA 类型是 bug 或 PR 向现有测试类添加一些测试时添加它。 请参见以下示例
      • Scala
        test("SPARK-12345: a short description of the test") {
          ...
        
      • Java
        @Test
        public void testCase() {
          // SPARK-12345: a short description of the test
          ...
        
      • Python
        def test_case(self):
            # SPARK-12345: a short description of the test
            ...
        
      • R
        test_that("SPARK-12345: a short description of the test", {
          ...
        
  5. 考虑是否应添加或更新基准测试结果作为更改的一部分,并根据需要通过在你的 fork 仓库中运行基准测试来生成基准测试结果。
  6. 运行所有测试 ./dev/run-tests 来验证代码仍然可以编译、通过测试并通过样式检查。 如果样式检查失败,请查看下面的代码样式指南。
  7. 将提交推送到你的分支。 这将触发你的 fork 仓库上的“构建和测试”和“报告测试结果”工作流程,并开始测试和验证你的更改。
  8. 针对 apache/sparkmaster 分支打开一个 pull request。(只有在特殊情况下,PR 才会针对其他分支打开)。这将触发 Spark 仓库上的“On pull request*”工作流程,该工作流程将查找/监视“你的” fork 仓库上成功的工作流程运行(如果正在运行,它将等待)。
    1. PR 标题应采用 [SPARK-xxxx][COMPONENT] Title 的形式,其中 SPARK-xxxx 是相关的 JIRA 编号,COMPONENT spark-prs.appspot.com 上显示的 PR 类别之一,Title 可以是 JIRA 的标题或更具体地描述 PR 本身的标题。
    2. 如果 pull request 仍然是正在进行的工作,因此尚未准备好合并,但需要推送到 GitHub 以方便审查,请在组件后添加 [WIP]
    3. 考虑识别从事更改代码的提交者或其他贡献者。 在 GitHub 中找到文件,然后单击“Blame”以查看最后更改代码的人员的逐行注释。 你可以在 PR 描述中添加 @username 以立即 ping 他们。
    4. 请声明该贡献是你的原创作品,并且你根据项目的开源许可将作品许可给项目。
  9. 相关的 JIRA(如果有)将被标记为“In Progress”,并且你的 pull request 将自动链接到它。 不需要成为 JIRA 的受让人即可进行工作,尽管欢迎你评论说你已经开始工作。
  10. 如果你的 pull request 中有与 SparkR 相关的更改,AppVeyor 将自动触发以在 Windows 上测试 SparkR,这大约需要一个小时。 与上述步骤类似,修复失败并推送新的提交,这将请求在 AppVeyor 中重新测试。

审查过程

  • 包括提交者在内的其他审阅者可能会对更改发表评论并提出修改建议。 只需将更多提交推送到同一分支即可添加更改。
  • 鼓励社区中的每个人进行活跃、礼貌、快速的技术辩论。 结果可能是拒绝整个更改。
  • 请记住,对 Spark 更关键部分(例如其核心和 SQL 组件)的更改将受到更多审查,并且可能需要比其他更改更多的测试和证明其正确性。
  • 审阅者可以使用诸如“我认为此补丁看起来不错”之类的评论来表明更改看起来适合合并。 Spark 使用 LGTM 约定来指示对补丁的最高级别的技术认可:只需评论“LGTM”一词即可。 它具体意味着:“我已经彻底检查了这一点,并且承担了与我自己编写补丁一样多的所有权”。 如果你评论 LGTM,你将需要帮助解决补丁上的错误或后续问题。 始终如一、明智地使用 LGTM 是作为审阅者在更广泛的社区中获得信誉的好方法。
  • 有时,其他更改将被合并,这会与你的 pull request 的更改发生冲突。 在冲突解决之前,无法合并 PR。 例如,可以通过 git remote add upstream https://github.com/apache/spark.git 添加 remote 以跟上上游更改,运行 git fetch upstream,然后运行 git rebase upstream/master 并手动解决冲突,然后将结果推送到你的分支来解决此问题。
  • 尽量对讨论做出回应,而不是让几天时间过去才回复

关闭你的 pull request / JIRA

  • 如果更改被接受,它将被合并,并且 pull request 以及相关的 JIRA(如果有)将自动关闭
    • 请注意,在极少数情况下,你被要求针对 master 之外的分支打开 pull request,你实际上必须手动关闭 pull request
    • JIRA 将分配给更改的主要贡献者,以表彰其功劳。 如果 JIRA 没有及时关闭和/或分配,请在 JIRA 上发表评论。
  • 如果你的 pull request 最终被拒绝,请立即将其关闭
    • ...因为提交者无法直接关闭 PR
    • 如果提交者发表了诸如“介意关闭此 PR 吗?”之类的评论,则大约一周后,Apache 的自动化流程将自动关闭 pull request。 这意味着提交者专门要求将其关闭。
  • 如果 pull request 很少或根本没有受到关注,请考虑改进描述或更改本身,并在几天后再次 ping 可能的审阅者。 考虑提出更容易包含的更改,例如更小和/或侵入性更小的更改。
  • 如果在从最相关的审阅者征求意见后数周未采纳,或者遇到了中性的反应,则结果可能被认为是“软否”。 在这种情况下,最好撤回并关闭 PR。
  • 如果 pull request 因被认为不是解决 JIRA 的正确方法而被关闭,则保持 JIRA 打开。 但是,如果审查清楚表明 JIRA 中标识的问题将不会通过任何 pull request 解决(不是问题,不会修复),则也解决 JIRA。

代码样式指南

请遵循现有代码库的样式。

  • 对于 Python 代码,Apache Spark 遵循 PEP 8,但有一个例外:行长最多可以为 100 个字符,而不是 79 个字符。
  • 对于 R 代码,Apache Spark 遵循 Google 的 R 样式指南,但有三个例外:行长最多可以为 100 个字符,而不是 80 个字符,函数名称没有限制,但它具有初始小写字母,并且允许使用 S4 对象/方法。
  • 对于 Java 代码,Apache Spark 遵循 Oracle 的 Java 代码约定和下面的 Scala 指南。 后者是首选。
  • 对于 Scala 代码,Apache Spark 遵循官方的 Scala 样式指南Databricks Scala 指南。 后者是首选。 要格式化 Scala 代码,请在提交 PR 之前运行 ./dev/scalafmt。

如有疑问

如果你不确定某种事物的正确样式,请尝试遵循现有代码库的样式。 查看代码中是否有其他示例使用了你的功能。 也可以在 dev@spark.apache.org 列表中提问和/或咨询提交者。

行为准则

Apache Spark 项目遵循 Apache 软件基金会行为准则行为准则适用于 Apache 软件基金会管理的所有空间,包括 IRC、所有公共和私人邮件列表、问题跟踪器、维基、博客、Twitter 以及我们的社区使用的任何其他沟通渠道。 专门针对面对面活动(即会议)的行为准则已编入已发布的 ASF 反骚扰政策。

我们希望正式或非正式地参与 Apache 社区或声称与基金会有任何关联的每个人,在任何与基金会相关的活动中,尤其是在代表 ASF 时,以任何身份遵守此行为准则。

此代码不是详尽或完整的。 它旨在提炼我们对协作、共享环境和目标的共同理解。 我们希望它在精神上和字面上都得到遵守,以便它可以丰富我们所有人以及我们参与的技术社区。

有关更多信息和具体指南,请参阅 Apache 软件基金会行为准则

最新消息

存档