最近,发现 Quarto book 不能发布到 <bookdown.org> 了,复现步骤如下:

先配置 RStudio Connect 账户

# 使用 CONNECT_API_KEY 部署
rsconnect::addServer("https://bookdown.org", "bookdown.org")
rsconnect::connectApiUser(
  account = "账户名", server = "bookdown.org",
  apiKey = Sys.getenv("CONNECT_API_KEY")
)

创建 quarto book

quarto create-project mybook --type book  

进入书籍根目录

cd mybook

进入 R 执行

quarto::quarto_publish_site()

出现如下错误

Preparing to deploy site...Error: HTTP 404
GET https://bookdown.org/applications?filter=account_id:103&filter=name:data-analysis-in-action&count=100&offset=0
404 page not found

如果我没记错,这个 Posit Connect API endpoint 的正确形式是

https://bookdown.org/__api__/applications

所以导致了 404。楼主可以看看是哪里出了问题导致 /__api__/ 部分没有被正确加入。

    nan.xiao 我猜测是 RStudio 改动了 API ,因为之前的部署姿势一直对的,7 月 8 号发现不对了。我想了想,这一天是迟早到来的, Quarto Book 不再适合推送到 bookdown.org ,因为我发现专门有个地方 https://quartopub.com/ 。所以,我干脆不再推送到 bookdown.org ,而是用 Netlify 部署 https://data-analysis-in-action.netlify.app/ 。也许 RStudio 会出来一个办法,怎么将 bookdown.org 迁移到 quartopub.com ?

    这个问题不重要了,既然是 Quarto Book 不必再推送到 bookdown.org 了。

    nan.xiao 佩服记忆力。
    下面假定有本叫 data-analysis-in-action 的书要部署到 bookdown.org 上。

    需要将

    rsconnect::addServer(url = "https://bookdown.org/", name = "bookdown.org")
    rsconnect::connectApiUser(
      account = "xiangyun", server = "bookdown.org",
      apiKey = Sys.getenv("CONNECT_API_KEY")
    )
    quarto::quarto_publish_site(
      name = "data-analysis-in-action", render = "none",
      server = "bookdown.org", account = "xiangyun",
      title = "Data Analysis in Action"
    )

    更改为

    # 更神奇的地方就是在这个地方不能加 __api__/
    rsconnect::addServer(url = "https://bookdown.org/", name = "bookdown.org")
    # connectApiUser 会自动在 bookdown.org 之后加 __api__/
    rsconnect::connectApiUser(
      account = "xiangyun", server = "bookdown.org",
      apiKey = Sys.getenv("CONNECT_API_KEY")
    )
    # 神奇的地方就是在这个地方修改 url
    rsconnect::addServer(url = "https://bookdown.org/__api__/", name = "bookdown.org")
    # quarto_publish_site 不会在 https://bookdown.org/ 之后加 __api__/  所以要修改
    quarto::quarto_publish_site(
      name = "data-analysis-in-action", render = "none",
      server = "bookdown.org", account = "xiangyun",
      title = "Data Analysis in Action"
    )

    就又可以用了。

      Cloud2016 可以到 quarto-r 建一个 issue。但是看了 Hadley 不久前建的 issue 以及最近的维护状态,感觉这部分重叠的功能未来也许会被 deprecate,这样的话直接用 rsconnect 来部署就好。

        nan.xiao 找到了一个用 rsconnect 替换 quarto 包部署的办法,只需替换最后那段调 quarto 包的代码

        rsconnect::deployApp(
          appDir = "_book",
          appId = Sys.getenv("CONTENT_ID"),
          contentCategory = "site",
          appName = "data-analysis-in-action",
          appTitle = "Data Analysis in Action",
          server = "bookdown.org", account = "xiangyun",
          forceUpdate = TRUE
        )

        rsconnect 1.0.0 发布后,不再需要下面这一行

        rsconnect::addServer(url = "https://bookdown.org/__api__/", name = "bookdown.org")

        rsconnect 1.0.0 发布后,可以用 deploySite 来部署。

        rsconnect::deploySite(
          siteName = "data-analysis-in-action",
          siteTitle = "Data Analysis in Action",
          server = "bookdown.org", account = "xiangyun",
          render = "none"
        )

        可见上面的问题很可能早就注意到了,并已经在开发版中解决。

        如果你的 bookdown 项目没有很特殊的依赖,与其手动本地编译部署,在长期看不如使用 Git-backed content 功能 让 Connect 自动探测内容更新再编译刷新。

        唯一需要的额外一步就是需要在 Git repo 中使用 rsconnect::writeManifest() 创建 manifest.json。这样所有的依赖版本就被固定了,类似于 renv.lock。只有在更新内容涉及更新依赖时需要重新生成这个文件。

          可能是依赖比较多,比较复杂,没成功,懒得折腾了。

          我是用 Docker 镜像打包了所有的依赖,然后用 Github Action 来测试的,本地也可以用这个镜像编译。最近,我发现用 Quarto 从命令行手动部署 Netlify 非常方便,GHA 每次编译成功后,推送到 Netlify 部署,也非常好。 避免了一旦 Git Push,Netlify 就开始自动部署的问题。因为,我想要只有当编译成功后,才开始部署的效果。

          nan.xiao 我突然想起来,你提的这个方法,和 Binder 结合起来应该不错,我以后再试试。Binder 用来自 Rocker 的 Ubuntu 镜像,然后 RStudio 对 Ubuntu 系统支持非常友好,R 包都预编译了,系统依赖也处理了。

            Cloud2016 理解,这种情况还是用一种支持自定义容器的方式在仓库一侧编译比较合适。

            也可以考虑 GitHub Actions 编译发布到一个分支,然后在 Connect 中选择导入那个分支。直接是一堆 HTML 静态文件的话,manifest.json 可能需要这样生成:

            rsconnect::writeManifest(
              appPrimaryDoc = "index.html",
              contentCategory = "site"
            )

            总之,选择适合自己的方案就好。前面我提出这个选项的初衷,是为了避免在本地或仓库侧通过 Connect API 推送的方式来布署,因为要自动化就会涉及到 credentials 管理的问题,换成使用 Connect 拉取的方式就避免了这类问题。

              nan.xiao 目前,我的 GHA 配置类似,先编译成功,出来一个文件夹 _book 然后将其部署到 Netlify 或 bookdown.org 。

              用自定义的容器镜像来测试,好处是一切都在掌控之中。有时候,出了错误,也有点懵逼,到处翻材料。

              构建镜像编译、部署

                Cloud2016 很好。感觉使用 Fedora 作为基础镜像是一个不太寻常的选择。很久以前用过一段这个发行版,软件版本更新策略有点激进,导致经常出现不太稳定的情况。好处是可以最先体验到新的软件,比如当时还在开发早期的 systemd。