使用持续集成 (CI) 进行发布
概述
持续集成 (CI) 指的是自动从版本控制系统中签入的代码发布内容的实践。虽然使用 CI 进行发布配置起来稍微复杂一些,但它有几个好处,包括:
每当源代码发生变化时,内容会自动发布(你不需要记住显式地渲染)。
在另一系统上进行渲染确保了你的代码是可复现的(但请注意,如果渲染有特殊要求,这可能是一把双刃剑——请参阅下面的 CI 渲染 讨论)。
不将渲染输出签入版本控制使得差异更小,减少了合并冲突。
本文介绍了如何使用 GitHub Actions(由 GitHub 运行的服务)、普通 shell 命令(可以与任何 CI 服务配合使用)以及 Posit Connect 实现 Quarto 的 CI。
CI 渲染
在开始使用 CI 服务器之前,你需要考虑你希望可执行代码(例如 R、Python 或 Julia 代码)在哪里运行,以及你希望 quarto render
在哪里运行。你可能会本能地假设你总是希望在 CI 服务器上运行所有内容,然而这样做会引入许多复杂性:
你需要确保 CI 环境中存在适当版本的 Quarto。
你需要在 CI 环境中重新构建所有依赖项(所需的 R、Python 或 Julia 包)。
如果你的代码需要任何特殊权限(例如数据库或网络访问),这些权限也需要在 CI 服务器上存在。
你的项目可能包含无法轻松执行的文档(例如几年前的博客文章,使用了较旧版本的包)。
鉴于上述情况,你可以将渲染视为一个从在本地环境中运行所有内容(包括 quarto render
)一直到在 CI 上远程运行所有内容的连续体:
本地执行和渲染 —— 在本地环境中运行所有内容,然后将输出(例如
_site
目录)签入版本控制。在这种情况下,CI 服务器只是确保每次提交时签入的内容被复制/部署到正确的位置。你可能会选择这种方法,以对 CI 服务器上需要存在的软件提出最小的要求。本地执行与 CI 渲染 —— 在本地执行 R、Python 或 Julia 代码,并使用 Quarto 的 冻结计算输出 功能将计算结果保存到
_freeze
目录中。在 CI 服务器上渲染站点(将使用存储在_freeze
中的计算结果)。当难以在 CI 服务器上完全重新执行代码时,使用这种方法。CI 执行和渲染 —— 在 CI 服务器上执行所有代码并进行渲染。虽然这是自动化和可复现性的黄金标准,但它将要求你捕获 R、Python 或 Julia 依赖项(例如在
renv.lock
文件或requirements.txt
文件中),并安排它们在 CI 服务器上安装。你还需要确保 CI 服务器上存在代码所需的权限(例如数据库访问)。
下面我们将描述如何使用 GitHub Actions、普通 Shell 命令(你应该能够将其适应任何 CI 环境)或 Posit Connect 实现这些策略。
GitHub Actions
GitHub Actions 是 GitHub 提供的持续集成服务,如果你的源代码已经托管在 GitHub 仓库中,这是一个极好的选择。Quarto 提供了一组 标准 GitHub Actions,使得安装 Quarto 并渲染和发布内容变得容易。
在这里了解如何将 GitHub Actions 与各种发布服务一起使用:
如果你想在其他工作流程中使用标准的 Quarto 操作,请参阅 Quarto 的 GitHub Actions 仓库。
Posit Connect
如果你将内容的源代码版本发布到 Posit Connect,可以配置 Connect 从 Git 仓库获取代码,然后在 Connect 服务器上渲染和执行。
要了解更多信息,请参阅 Posit Connect 的 Git 支持的内容 文档。
Shell 命令
本节介绍如何在无法进行用户交互的服务器上使用 quarto publish
命令。这涉及以下步骤:
- 渲染你的内容。
- 指定发布位置(服务/服务器、发布目标 ID 等)。
- 提供适当的发布凭证。
例如,这里有一个基于项目根目录下的 _publish.yml
文件信息发布到 Netlify 的 shell 脚本:
Terminal
# 来自 https://app.netlify.com/user/applications 的凭证
export NETLIFY_AUTH_TOKEN="45fd6ae56c"
# 发布到 _publish.yml 中提供的 Netlify 站点 ID
quarto publish netlify
以下是 _publish.yml
的内容:
- source: project
netlify:
- id: "5f3abafe-68f9-4c1d-835b-9d668b892001"
url: "https://tubular-unicorn-97bb3c.netlify.app"
以下是另一种在命令行中提供发布目标的变体:
Terminal
quarto publish netlify --id 5f3abafe-68f9-4c1d-835b-9d668b892001
下面我们将介绍发布脚本的各种组件,并提供一些额外的完整示例。
发布前的渲染
默认情况下,当你执行发布命令时,你的网站或文档将自动重新渲染:
Terminal
quarto publish
这通常是推荐的,因为它确保你基于源代码的最新版本进行发布。
如果你想单独渲染(或根本不渲染),可以使用 --no-render
选项:
Terminal
quarto publish --no-render
默认情况下,调用 quarto publish
将执行项目中包含的所有 R、Python 或 Julia 代码。这意味着你需要确保 CI 服务器上安装了这些工具的必要版本(以及任何所需的包)。如何做到这一点不在本文的讨论范围内——要了解更多关于保存和恢复依赖关系的信息,请参阅关于 虚拟环境 的文章。
如果你想在本地执行代码,然后在 CI 上仅进行 Markdown 渲染,可以使用 Quarto 的 冻结 功能。例如,如果你在 _quarto.yml
文件中添加以下内容:
execute:
freeze: true
那么当你在本地渲染时,计算将运行并将结果保存在项目根目录的 _freeze
文件夹中。然后,当你在 CI 服务器上运行 quarto publish
或 quarto render
时,这些计算不需要重新运行(服务器上只会进行 Markdown 渲染)。
发布目标
有两种方法可以为 quarto publish
命令指定发布目标:
- 通过从之前的发布创建的
_publish.yml
文件的内容。 - 使用命令行参数(例如
--id
和--server
)。
当你执行 quarto publish
命令时,你的发布目标记录会写入与源代码一起的 _publish.yml
文件中。例如:
- source: project
netlify:
- id: "5f3abafe-68f9-4c1d-835b-9d668b892001"
url: "https://tubular-unicorn-97bb3c.netlify.app"
你可以将 _publish.yml
文件检入源代码管理,以便在从 CI 服务器发布时可用。如果你在没有参数的情况下执行 quarto publish
命令,并且项目目录中有上述 _publish.yml
,那么发布将针对具有指定 id
的 Netlify:
Terminal
quarto publish netlify
你也可以通过显式的命令行参数指定发布目标。例如:
Terminal
quarto publish netlify --id 5f3abafe-68f9-4c1d-835b-9d668b892001
如果你在 _publish.yml
中有多个发布目标,则可以使用 --id
选项从中选择。
发布凭证
你可以使用环境变量或命令行参数指定发布凭证。以下环境变量被各种服务识别:
服务 | 变量 |
---|---|
Quarto Pub | QUARTO_PUB_AUTH_TOKEN |
Netlify | NETLIFY_AUTH_TOKEN |
Posit Connect | CONNECT_SERVER 和 CONNECT_API_KEY |
Confluence | CONFLUENCE_AUTH_TOKEN 、CONFLUENCE_USER_EMAIL 和 CONFLUENCE_DOMAIN |
在调用 quarto publish
之前,在你的脚本中设置这些环境变量。例如:
Terminal
export NETLIFY_AUTH_TOKEN="45fd6ae56c"
quarto publish netlify
注意,你也可以将发布目标 --id
作为命令行参数指定。例如:
Terminal
export CONNECT_SERVER=https://connect.example.com/
export CONNECT_API_KEY=7C0947A852D8
quarto publish connect --id DDA36416-F950-4647-815C-01A24233E294
完整示例
以下是一些完整的示例,展示了编写发布 shell 脚本的各种方式:
Terminal
# 基于 _publish.yml 发布(不渲染)到 quarto pub
export QUARTO_PUB_AUTH_TOKEN="45fd6ae56c"
quarto publish quarto-pub --no-render
Terminal
# 渲染并基于 _publish.yml 发布到 netlify
export NETLIFY_AUTH_TOKEN="45fd6ae56c"
quarto publish netlify
Terminal
# 基于显式 id 发布(不渲染)到 netlify
export NETLIFY_AUTH_TOKEN="45fd6ae56c"
quarto publish netlify --id DDA36416-F950-4647-815C-01A24233E294 --no-render
Terminal
# 根据 _publish.yml 发布(不渲染)到 Connect
export CONNECT_SERVER=https://connect.example.com/
export CONNECT_API_KEY=7C0947A852D8
quarto publish connect --no-render
Terminal
# 渲染并发布到带有显式ID的Connect
export CONNECT_SERVER=https://connect.example.com/
export CONNECT_API_KEY=7C0947A852D8
quarto publish connect --id DDA36416-F950-4647-815C-01A24233E294
Terminal
# 根据_publish.yml渲染并发布到Confluence
export CONFLUENCE_AUTH_TOKEN=7C0947A852D8
export CONFLUENCE_USER_EMAIL=email@domain.com
export CONFLUENCE_DOMAIN=https://domain.atlassian.net/
quarto publish confluence --no-browser --no-prompt