rstudio / rsconnect

Publish Shiny Applications, RMarkdown Documents, Jupyter Notebooks, Plumber APIs, and more
http://rstudio.github.io/rsconnect/
129 stars 79 forks source link

quarto: engines metadata is vector, not singular #1017

Closed aronatkins closed 8 months ago

aronatkins commented 8 months ago

Quarto content can report multiple engines, which arrives as the metadata argument to deployApp() and others.

That metadata is eventually serialized into a deployment record. The presence of multiple engines causes rsconnect to write two records into a single DCF file.

record <- rsconnect:::deploymentRecord(
    name = "the-name",
    title = "the-title",
    username = "the-username",
    account = "the-account",
    server = "the-server",
    metadata = list(quarto_engines = c("knitr","markdown"))
)
t <- tempfile()
rsconnect:::writeDeploymentRecord(record, t)
read.dcf(t)
#>      name       title       username       account       server       hostUrl
#> [1,] "the-name" "the-title" "the-username" "the-account" "the-server" ""     
#> [2,] "the-name" "the-title" "the-username" "the-account" "the-server" ""     
#>      appId bundleId url version quarto_engines
#> [1,] ""    ""       ""  "1"     "knitr"       
#> [2,] ""    ""       ""  "1"     "markdown"

We serialize envVars to a comma-separated list, but take no similar action for other multi-value fields.

https://github.com/rstudio/rsconnect/blob/525289dd91cd806c64cf79233c643d2f6bf2409a/R/deployments.R#L73-L76

https://github.com/rstudio/rsconnect/blob/525289dd91cd806c64cf79233c643d2f6bf2409a/R/deployments.R#L141

aronatkins commented 8 months ago

Discovered while investigating https://github.com/rstudio/rsconnect/issues/1014

aronatkins commented 8 months ago

The RStudio IDE sends a vector of engines:

https://github.com/rstudio/rstudio/blob/afbabb533c00add040c124126438177457ba5592/src/cpp/session/modules/SessionRSConnect.cpp#L110-L111

The quarto R package also provides a vector:

https://github.com/quarto-dev/quarto-r/blob/2fd494eb69f0dd6495bf6f8303075f451f8e8186/R/publish.R#L399-L404

Additionally, rsconnect can compute a vector of engines:

https://github.com/rstudio/rsconnect/blob/525289dd91cd806c64cf79233c643d2f6bf2409a/R/appMetadata-quarto.R#L18-L22

The vector of engines is used when determining if R or Python are needed: https://github.com/rstudio/rsconnect/blob/525289dd91cd806c64cf79233c643d2f6bf2409a/R/appDependencies.R#L142-L143 https://github.com/rstudio/rsconnect/blob/525289dd91cd806c64cf79233c643d2f6bf2409a/R/bundle.R#L132

That data is also sent in the manifest.json to guide environment reconstruction. https://github.com/rstudio/rsconnect/blob/525289dd91cd806c64cf79233c643d2f6bf2409a/R/bundle.R#L229-L230

We should convert metadata fields from vectors to a comma-separated string when writing the DCF file, but can probably leave them in that form when the DCF file is read.

aronatkins commented 8 months ago

A consequence of this problem: The RStudio IDE could show two target deployments when one existed, and publishing attempts fail with errors like:

── Preparing for deployment ────────────────────────────────────────────────────
Error in `rsconnect::deployApp()`:
! This directory has been previously deployed in multiple places.
Please use `appName`, `server` or `account` to disambiguate.
Known applications:
• quarto-failed-republish (server: SERVERNAME / username: USERNAME):
  <https://SERVERNAME/content/cf5960ea-484f-4285-9207-2b17aca4a27e/>
• quarto-failed-republish (server: SERVERNAME / username: USERNAME):
  <https://SERVERNAME/content/cf5960ea-484f-4285-9207-2b17aca4a27e/>
Backtrace:
    ▆
 1. └─rsconnect::deployApp(...)
 2.   └─rsconnect:::deploymentTarget(...)
 3.     └─rsconnect:::disambiguateDeployments(appDeployments, error_call = error_call)
 4.       └─rsconnect:::cli_menu(...)
 5.         └─cli::cli_abort(c(header, not_interactive), .envir = .envir, call = error_call)
 6.           └─rlang::abort(...)
Execution halted