posit-dev / posit-dev/rsconnect-python
Apply .posit/publish config Connect-side settings: post-deploy hook + `rsconnect sync`
Nessuno ha ancora preso questa issue.
- Lingua principale
- Python
- Stelle
- 37
- Fork
- 28
- Merge medio
- 1g 3h
- PR unite (30g)
- 7
Descrizione
Summary
Follow-up to #830. That PR made rsconnect-python read/write Posit Publisher's
.posit/publish TOML, drive bundling from a config's files, and propagate
integration_requests into manifest.json. What it does not do is apply the
config's Connect-side settings — the fields that Publisher applies through the
Connect API after upload rather than through manifest.json.
Today those fields (description, connect.runtime.*, connect.access.*,
connect.kubernetes.*, environment, secrets) are round-tripped and preserved
in the config, but a rsconnect deploy/redeploy from a Publisher-authored config
still does not apply them to the content. As of #830, redeploy warns when a
resolved config sets any of these, so the gap is no longer silent — but the
settings themselves still aren't pushed to Connect. This issue tracks closing that
gap in two pieces:
- A post-deploy hook that applies the config's Connect-side settings after a
successful deploy (mirroring Publisher). - A
rsconnect synccommand that applies the current TOML settings to
already-deployed content ad hoc, without rebuilding/redeploying a bundle —
for when a user edits the config and just wants Connect updated.
Where each config field is applied (reference: Posit Publisher)
Publisher builds the manifest from the config, then makes two kinds of API calls.
Verified in the publisher repo:
extensions/vscode/src/bundler/{manifestFromConfig,connectContentFromConfig}.ts
and extensions/vscode/src/publish/{connectPublish,publishShared}.ts.
| Config field | Channel | Status in rsconnect after #830 |
|---|---|---|
type, entrypoint, python, quarto, r, jupyter, has_parameters |
manifest.json | ✅ (from inspection) |
integration_requests |
manifest.json | ✅ propagated in #830 |
title |
PATCH /v1/content/{guid} |
✅ (already applied via executor) |
description |
PATCH /v1/content/{guid} |
❌ not applied |
connect.runtime.* |
PATCH /v1/content/{guid} |
❌ not applied |
connect.access.* |
PATCH /v1/content/{guid} |
❌ not applied |
connect.kubernetes.* |
PATCH /v1/content/{guid} |
❌ not applied |
environment (env-var map) |
env-var API (setEnvVars) |
⚠️ CLI path exists, not sourced from config |
secrets |
env-var API (setEnvVars, merged; secrets override) |
❌ not applied |
Fields to apply via PATCH /v1/content/{guid}
Built by Publisher's connectContentFromConfig:
- metadata:
title,description(Connect rejectsdescription> 4096 chars) - runtime (
connect.runtime.*):connection_timeout,read_timeout,
init_timeout,idle_timeout,max_processes,min_processes,
max_conns_per_process,load_factor - access (
connect.access.*):run_as,run_as_current_user - kubernetes (
connect.kubernetes.*):memory_request,memory_limit,
cpu_request,cpu_limit,amd_gpu_limit,nvidia_gpu_limit,
service_account_name,default_image_name,
default_r_environment_management,default_py_environment_management
Fields to apply via the env-var API
-
environment(non-secret name→value map) is read straight from the config
and set on the content. -
secrets— follow Publisher's model exactly. The config'ssecretsarray
holds secret names only; values are never stored in the TOML or anywhere
on disk. Publisher keeps values in-memory in its webview for the session, does
not persist them (only credentials/Snowflake tokens use VS Code SecretStorage),
and re-prompts (names reload with empty values) on the next session. At publish
it sends only the names the user actually filled in, merges them over
environmentviamergeEnvVars(secret values win on key collision), sets them
on the content flagged as secret (encrypted/masked), and omits any
declared name with no value (it never sends empty values).CLI analogue (the faithful equivalent of Publisher's per-session entry): at
deploy/sync time, source each declared secret's value ad hoc — from the
process environment ($NAME) and/or explicit--secret NAME=VALUEflags — never
from a file. Merge overenvironment(secret wins), set flagged as secret, and
skip any declared name with no supplied value (warn, don't fail). rsconnect
already has an env-var code path (--environment/ executorenv_vars) to reuse
for the actual set call.
Part 1 — Post-deploy hook
Goal: after a successful Connect/SPCS deploy that has an applicable
.posit/publish config, apply that config's Connect-side settings to the deployed
content.
Design sketch:
- Add a
RSConnectClientmethod for the content-settings PATCH
(PATCH v1/content/{guid}) if one does not already exist, plus reuse the existing
env-var setter. - Add a builder in
rsconnect/publisher/that maps aPublisherConfigto the
content-settings payload (the rsconnect analogue ofconnectContentFromConfig)
and to the merged env-var map (analogue ofmergeEnvVars). Readconnect.*,
environment,secrets,descriptionfrom the config (they currently live in
PublisherConfig.extra; consider promoting to managed fields). - Call it from
RSConnectExecutorafterwait_for_taskcompletes, gated to
Connect/SPCS (same gate as_save_publisher_metadata), best-effort (warn,
don't fail the deploy — the bundle already deployed).
Validation / edge cases (mirror Publisher's preflight):
- Runtime settings are invalid on
staticcontent → skip/warn. - Validate
min_processes <= max_processes; clamp/validate*_request <= *_limit;
respect serverscheduler.*_limitmaxima where discoverable. run_as/service_account_namerequire admin;run_as_current_userand
Kubernetes require server license/config — surface a clear warning when the
server rejects, rather than aborting.secrets: follow Publisher's model (see the env-var section above) — names live
in the TOML, values are sourced ad hoc at run time ($NAME/--secret NAME=VALUE), never persisted; unset names are skipped, not sent empty; supplied
values are set flagged as secret and overrideenvironmenton key collision.- No-op cleanly when the config declares none of these fields.
Part 2 — rsconnect sync command
Goal: apply the TOML config's Connect-side settings to already-deployed content
ad hoc, without rebuilding or redeploying a bundle. This is the "I edited the
config, push the settings to Connect" path.
Behavior:
rsconnect sync [PATH]—PATHdefaults to the current directory, like
redeploy.- Resolves the applicable
.posit/publishconfig (single,--config-name, or
entrypoint match) and the target content GUID from the matching deployment
record. - Server targeting: accept
--server/--name/--api-key; when none are
given, default to the server in the config / deployment record, resolving a
saved rsconnect-python credential by normalized URL (reuse
_find_saved_server_by_url, asredeploydoes). - Applies exactly the Part 1 post-deploy hook logic against the resolved content —
no bundle build, no upload, no new deployment record (though it may refresh
the record's timestamp/settings snapshot; TBD). - Errors clearly if there is no deployment record (nothing to sync to) and no
destination was supplied.
Shared code: Part 1 and Part 2 must call the same
config→(content-settings + env-vars)→API applier so behavior can't drift.
Acceptance criteria
- A config's
description,connect.runtime.*,connect.access.*, and
connect.kubernetes.*are applied to the content on deploy/redeploy
(Connect/SPCS only), best-effort. - A config's
environmentis applied as env vars on deploy/redeploy. -
secretsfollow Publisher's model: names only in the TOML; values sourced ad
hoc ($NAME/--secret NAME=VALUE), never persisted; unset names skipped;
supplied values set flagged as secret and overridingenvironmenton
collision. -
rsconnect sync [PATH]applies the same settings ad hoc to already-deployed
content, with no bundle rebuild. -
synctargets the config/record server by default and honors
--server/--name/--api-keyoverrides. - Server-side validation failures (limits, licensing, admin-only) warn clearly
without corrupting the deploy. - Tests cover the config→payload mapping, the deploy hook, and
sync
(including default vs. explicit server targeting). - CHANGELOG updated.
References
- PR: #830
- Publisher config→content-settings:
extensions/vscode/src/bundler/connectContentFromConfig.ts - Publisher env-var merge:
extensions/vscode/src/publish/publishShared.ts(mergeEnvVars) - Publisher secrets model (names in config, values in-memory per session, not persisted):
extensions/vscode/webviews/homeView/src/stores/home.ts(in-memorysecretsmap, reloaded with empty values),extensions/vscode/src/views/homeView.ts - Publisher publish sequence + preflight validation:
extensions/vscode/src/publish/connectPublish.ts - Already-implemented manifest side (integration_requests):
rsconnect/bundle.py(overlay_manifest),rsconnect/publisher/store.py(config_manifest_overlay)
Guida per i contributori
Apri la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Direzione di ricerca
Inizia da RSConnectExecutor, dalla content API di RSConnectClient e dal percorso env-var esistente, quindi esamina rsconnect/publisher/ e la logica dei deployment record utilizzata da redeploy. Confronta le implementazioni di Publisher indicate, in particolare connectContentFromConfig.ts e mergeEnvVars, prima di progettare l'applicatore di configurazione condiviso e l'entry point di sync. Il lavoro è completato quando deploy e sync applicano le impostazioni documentate e sono presenti test per il mapping, gli hook, il targeting del server, gli avvisi di validazione e l'assenza di una ricostruzione del bundle.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Valutazione
- Stack tecnologico
- python
- Ambito
- api, cli
- Tipo di issue
- Funzionalità
- Difficoltà
- 5/5
- Tempo stimato
- Più di una settimana
- Stato di attività
- Tranquilla
- Chiarezza
- Abbastanza chiara
- Idoneità per principianti
- 35/100