准备 Spark 发布

Spark 中的发布经理角色意味着您需要负责几项不同的事情

准备您的设置

如果您是新的发布经理,您可以阅读以下内容了解流程

准备 GPG 密钥

如果您已上传密钥,可以跳过此部分。

生成密钥

这里是 gpg 2.0.12 的示例。如果您使用 gpg 1 系列版本,请参考 generate-key 获取详细信息。

$ gpg --full-gen-key
gpg (GnuPG) 2.0.12; Copyright (C) 2009 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Please select what kind of key you want:
   (1) RSA and RSA (default)
   (2) DSA and Elgamal
   (3) DSA (sign only)
   (4) RSA (sign only)
Your selection? 1
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 4096
Requested keysize is 4096 bits
Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0) 
Key does not expire at all
Is this correct? (y/N) y

GnuPG needs to construct a user ID to identify your key.

Real name: Robert Burrell Donkin
Email address: rdonkin@apache.org
Comment: CODE SIGNING KEY
You selected this USER-ID:
    "Robert Burrell Donkin (CODE SIGNING KEY) <rdonkin@apache.org>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
gpg: key 04B3B5C426A27D33 marked as ultimately trusted
gpg: revocation certificate stored as '/home/ubuntu/.gnupg/openpgp-revocs.d/08071B1E23C8A7E2CA1E891A04B3B5C426A27D33.rev'
public and secret key created and signed.

pub   rsa4096 2021-08-19 [SC]
      08071B1E23C8A7E2CA1E891A04B3B5C426A27D33
uid                      Jack (test) <Jack@mail.com>
sub   rsa4096 2021-08-19 [E]

请注意,公钥的最后 8 位数字 (26A27D33) 是 密钥 ID

上传密钥

生成公钥后,我们应该将其上传到 公共密钥服务器

$ gpg --keyserver hkps://keys.openpgp.org --send-key 26A27D33

请参考 keyserver-upload 获取详细信息。

用您的代码签名密钥更新 KEYS 文件

要获取代码签名密钥(又称 ASCII-armored 公钥),请运行命令

$ gpg --export --armor 26A27D33

然后通过以下方式将生成的密钥追加到 KEYS 文件中

# Move dev/ to release/ when the voting is completed. See Finalize the Release below
svn co --depth=files "https://dist.apache.org/repos/dist/dev/spark" svn-spark
# edit svn-spark/KEYS file
svn ci --username $ASF_USERNAME --password "$ASF_PASSWORD" -m"Update KEYS"

如果您想在另一台机器上进行发布,可以通过 gpg --export-secret-keysgpg --import 命令将您的私钥传输到该机器。

返回顶部

安装 Docker

创建发布候选版本的脚本通过 Docker 运行。您需要在运行这些脚本之前安装 Docker。请确保您可以以非 root 用户身份运行 Docker。有关更多详细信息,请参阅 https://docs.dockerd.com.cn/install/linux/linux-postinstall

准备发布候选版本

准备发布的主要步骤是创建发布分支。这通过标准的 Git 分支机制完成,一旦分支创建,就应该向社区宣布。

返回顶部

发布候选版本

如果这不是第一个 RC,请确保自上次 RC 以来已解决的 JIRA 问题被标记为 ResolvedTarget Versions 设置为该发布版本。

要跟踪任何针对此发布的待定 PR 问题,请在 JIRA 中创建过滤器,查询如下:project = SPARK AND "Target Version/s" = "12340470" AND status in (Open, Reopened, "In Progress")

要使用的目标版本字符串值,请通过查找具有该目标版本的现有问题并单击版本(例如,查找针对 2.2.1 的问题并单击其目标版本字段的版本链接)来找到与发布对应的数字值

通过 git log 验证它们是否真的进入了新的 RC。检查带有 release-notes 标签的 JIRA 问题,并确保它们在相关的迁移指南中针对重大更改进行了文档说明,或稍后在网站上的发布新闻中进行了文档说明。

返回顶部

使用自动化工具创建发布候选版本

要发布候选版本,有 4 个步骤

  1. 为发布候选版本创建 Git 标签。
  2. 打包发布二进制文件和源代码,并将其上传到 Apache 临时 SVN 仓库。
  3. 创建发布文档,并将其上传到 Apache 临时 SVN 仓库。
  4. 将快照发布到 Apache 临时 Maven 仓库。

发布候选版本的过程已通过 dev/create-release/do-release-docker.sh 脚本自动化。运行此脚本,输入所需信息,然后等待其完成。您还可以通过 -s 选项执行单个步骤。请运行 do-release-docker.sh -h 查看更多详细信息。

返回顶部

对发布候选版本进行投票

发布投票在 Apache Spark 开发者邮件列表(PMC 正在投票)上进行。查看过去的投票帖子以了解其进展。邮件应遵循 此格式

  • 使用 https://s.apache.org/ 为完整的 JIRA 列表创建缩短的链接
  • 如果可能,在邮件中附上发布说明草稿
  • 确保投票截止时间采用 UTC 格式。使用此脚本生成它
  • 确保邮件是文本格式且链接正确

投票结束后,您还应该发送一封包含总计的摘要邮件,主题类似于 [VOTE][RESULT] ...

最终确定发布

请注意,dev/create-release/do-release-docker.sh 脚本(finalize 步骤)自动化了以下大部分步骤,除了

  • 更新 Algolia Crawler 的配置
  • 从镜像网络中删除旧版本
  • 更新 Spark 网站的其余部分
  • 创建并上传 Spark Docker 镜像
  • 创建公告

请在每一步之后手动验证结果。

返回顶部

上传到 Apache 发布目录

小心!

此步骤不可逆,请确保您选择了正确的临时仓库。一旦将工件移动到发布文件夹,它们就无法删除。

投票通过后,要将二进制文件上传到 Apache 镜像,您需要将二进制文件从开发目录(投票的所在地)移动到发布目录。这种“移动”是您将内容添加到实际发布目录的唯一方式。(注意:只有 PMC 可以移动到发布目录)

# Move the sub-directory in "dev" to the
# corresponding directory in "release"
$ export SVN_EDITOR=vim
$ svn mv https://dist.apache.org/repos/dist/dev/spark/v1.1.1-rc2-bin https://dist.apache.org/repos/dist/release/spark/spark-1.1.1

# If you've added your signing key to the KEYS file, also update the release copy.
svn co --depth=files "https://dist.apache.org/repos/dist/release/spark" svn-spark
curl "https://dist.apache.org/repos/dist/dev/spark/KEYS" > svn-spark/KEYS
(cd svn-spark && svn ci --username $ASF_USERNAME --password "$ASF_PASSWORD" -m"Update KEYS")

验证资源是否存在于 https://apache.org/dist/spark/ 中。它们可能需要一段时间才能可见。这将在整个 Apache 网络中进行镜像。在 https://checker.apache.org/projs/spark.html 检查发布的检查器结果。

对于 Maven 中央仓库,您可以从 Apache Nexus Repository Manager 发布。这已经由 release-build.sh publish-release 步骤填充。登录,打开 Staging Repositories,找到投票通过的那个(例如 https://repository.apache.org/content/repositories/orgapachespark-1257/ 的 orgapachespark-1257),选择并点击 Release 并确认。如果成功,它应该出现在 https://repository.apache.org/content/repositories/releases/org/apache/spark/spark-core_2.11/2.2.1/https://repository.apache.org/content/groups/maven-staging-group/org/apache/spark/spark-core_2.11/2.2.1/(查找正确的发布版本)下。一段时间后,这将自动同步到 Maven Central

返回顶部

上传到 PyPI

您需要自己的 PyPI 账户。如果您没有可以访问 PyPI 上的 pysparkpyspark-connect 项目的 PyPI 账户,请请求 PMC 授予这两个项目的权限。

工件可以使用 twine 上传。只需运行

twine upload -u __token__  -p $PYPI_API_TOKEN \
    --repository-url https://upload.pypi.org/legacy/ \
    "pyspark-$PYSPARK_VERSION.tar.gz" \
    "pyspark-$PYSPARK_VERSION.tar.gz.asc"

调整命令以匹配新发布的文件。如果由于某种原因 twine 上传不正确(例如 http 失败或其他问题),您可以将工件重命名为 pyspark-version.post0.tar.gz,从 PyPI 中删除旧工件并重新上传。

返回顶部

从仓库中删除 RC 工件

注意!如果您没有为已批准的 RC 备份文档,这是您最后一次可以进行备份。这将用于在接下来的几个步骤中将文档上传到网站。在删除目录之前,从 svn 中检出文档。

投票通过并您将批准的 RC 移至发布仓库后,您应该从临时仓库中删除 RC 目录。例如

RC=v3.5.2-rc3 && \
  svn rm https://dist.apache.org/repos/dist/dev/spark/"${RC}"-bin/ \
  https://dist.apache.org/repos/dist/dev/spark/"${RC}"-docs/ \
  -m"Removing RC artifacts."

请务必也从 Apache Nexus Repository Manager 中删除未发布的临时仓库。

返回顶部

从镜像网络中删除旧版本

Spark 始终在镜像网络中保留每个分支的最新维护发布。要删除旧版本,只需使用 svn rm

$ svn rm https://dist.apache.org/repos/dist/release/spark/spark-1.1.0

您还需要更新 js/download.js 以指示该版本不再被镜像,以便在网站上生成正确的链接。

返回顶部

更新 Spark Apache 仓库

检出通过的发布候选版本的标签提交并应用正确的版本标签。

$ git tag v1.1.1 v1.1.1-rc2 # the RC that passed
$ git push apache v1.1.1

返回顶部

更新 Algolia Crawler 的配置

Spark 文档网站 上的搜索框利用了 Algolia Crawler。在发布之前,请在 Algolia Crawler Admin Console 上使用新版本更新 Apache Spark 的爬虫配置。如果您无法访问配置,请联系 Gengliang WangXiao Li 寻求帮助。

返回顶部

更新 Spark 网站

上传生成的文档

网站仓库位于 https://github.com/apache/spark-website

建议不要删除最新 RC 生成的文档,以便我们可以直接将其复制到 spark-website,否则您需要重新构建文档。

# Build the latest docs
$ git checkout v1.1.1
$ cd docs
$ PRODUCTION=1 bundle exec jekyll build

# Copy the new documentation to Apache
$ git clone https://github.com/apache/spark-website
...
$ cp -R _site spark-website/site/docs/1.1.1

# Update the "latest" link
$ cd spark-website/site/docs
$ rm latest
$ ln -s 1.1.1 latest

更新 Spark 网站的其余部分

接下来,更新 Spark 网站的其余部分。查看以前的版本是如何记录的(所有 HTML 文件更改都是由 jekyll 生成的)。特别是

  • 更新 documentation.md 以添加新版本的文档链接
  • 将新版本添加到 js/downloads.js (注意版本的顺序)
  • 更新 downloads.md 以在链接示例中使用最新版本
  • 将新版本添加到 site/static/versions.json (注意版本的顺序)[用于 PySpark 文档的 spark version drop down]
  • 检查 security.md 是否有需要更新的内容
$ git add 1.1.1
$ git commit -m "Add docs for Spark 1.1.1"

然后,创建发布说明。前往 JIRA 中的发布页面,从列表中选择发布版本,然后单击“Release Notes”。复制此 URL,然后在 s.apache.org 上创建一个短 URL,登录您的 Apache 账户,并选择一个 ID,例如 spark-2.1.2。在 releases/_posts 下创建一个新的发布帖子,以包含此短 URL。帖子的日期应为您创建它的日期。

然后运行 bundle exec jekyll build 以更新 site 目录。

考虑到拉取请求会很大,请将代码更改和生成的 site 目录的提交分开,以便于审查。

将更改合并到 asf-site 分支后,您可能需要创建一个后续的空提交以强制 ASF 的 git 与网站以及 GitHub 镜像之间的同步。出于某种原因,此仓库的同步似乎不可靠。

另外,请确保在 JIRA 上将版本标记为已发布。像上面那样找到发布页面,例如,https://issues.apache.org/jira/projects/SPARK/versions/12340295,然后单击右侧的“Release”按钮并输入发布日期。

(通常,这仅适用于主要版本和次要版本,不适用于补丁版本)贡献者列表可以通过 此脚本 自动生成。它接受与当前版本对应的标签以及与上一个版本对应的标签(不包括维护版本)。例如,如果您正在发布 Spark 1.2.0,请将当前标签设置为 v1.2.0-rc2,将上一个标签设置为 v1.1.0。一旦生成了初始贡献者列表,很可能会出现关于作者姓名未正确翻译的警告。要解决此问题,请运行 此另一个脚本,该脚本从 GitHub 和 JIRA 获取潜在的替换。例如

$ cd dev/create-release
# Set RELEASE_TAG and PREVIOUS_RELEASE_TAG
$ export RELEASE_TAG=v1.1.1
$ export PREVIOUS_RELEASE_TAG=v1.1.0
# Generate initial contributors list, likely with warnings
$ ./generate-contributors.py
# Set GITHUB_OAUTH_KEY.
$ export GITHUB_OAUTH_KEY=blabla
# Set either JIRA_ACCESS_TOKEN (for 4.0.0 and later) or JIRA_USERNAME / JIRA_PASSWORD.
$ export JIRA_ACCESS_TOKEN=blabla
$ export JIRA_USERNAME=blabla
$ export JIRA_PASSWORD=blabla
# Translate names generated in the previous step, reading from known_translations if necessary
$ ./translate-contributors.py

此外,如果您希望为大型补丁的开发者提供更具体的贡献,您可以使用以下命令来识别大型补丁。必须格外小心,确保不计算来自先前版本的提交,因为 git 无法轻易关联已回溯到不同分支的提交。

# Determine PR numbers closed only in the new release
$ git log v1.1.1 | grep "Closes #" | cut -d " " -f 5,6 | grep Closes | sort > closed_1.1.1
$ git log v1.1.0 | grep "Closes #" | cut -d " " -f 5,6 | grep Closes | sort > closed_1.1.0
$ diff --new-line-format="" --unchanged-line-format="" closed_1.1.1 closed_1.1.0 > diff.txt

# Grep expression with all new patches
$ EXPR=$(cat diff.txt | awk '{ print "\\("$1" "$2" \\)"; }' | tr "\n" "|" | sed -e "s/|/\\\|/g" | sed "s/\\\|$//")

# Contributor list
$ git shortlog v1.1.1 --grep "$EXPR" > contrib.txt

# Large patch list (300+ lines)
$ git log v1.1.1 --grep "$expr" --shortstat --oneline | grep -B 1 -e "[3-9][0-9][0-9] insert" -e "[1-9][1-9][1-9][1-9] insert" | grep SPARK > large-patches.txt

返回顶部

创建并上传 Spark Docker 镜像

apache/spark-docker 提供 Dockerfile 和 GitHub Action 用于发布的 Spark Docker 镜像,请按照 说明 创建和上传 Docker 镜像。

返回顶部

创建公告

一旦一切正常(网站文档,网站更改),请在网站上创建公告,然后向邮件列表发送一封主题类似于 [ANNOUNCE] ... 的电子邮件。要创建公告,请在 news/_posts 下创建一个帖子,然后运行 bundle exec jekyll build

享用您选择的成人饮品,祝贺您成功发布 Spark。

返回顶部