Skip to content

Add a command to deploy a previously downloaded bundle (.tar.gz) directly #790

Description

@nealrichardson

Problem

A user has a content bundle (.tar.gz) downloaded from one Connect instance and wants to publish it to another. Today there is no single command that takes a downloaded bundle and re-deploys it.

The current workaround is to unpack the bundle and use deploy manifest:

mkdir mycontent && tar -xzf bundle.tar.gz -C mycontent
rsconnect deploy manifest mycontent/manifest.json --server ... --api-key ...

Proposal

Add a command (e.g. rsconnect deploy bundle <bundle.tar.gz>) that deploys a downloaded bundle directly.

Importantly, this should not extract and re-bundle. A downloaded bundle is already exactly the tarball that the deploy machinery uploads, so the extract → deploy manifestmake_manifest_bundle round trip is wasted work (and risks producing a slightly different bundle than the one downloaded).

Looking at RSConnectExecutor in rsconnect/api.py:

  • make_bundle(func, ...) (api.py:1317) just sets self.bundle to a file-like tarball.
  • deploy_bundle() (api.py:1358) uploads exactly self.bundle.

So for a downloaded bundle we can skip make_bundle entirely and set self.bundle to the opened tarball directly. The deploy chain is then identical to deploy manifest:

ce.validate_server()
  .validate_app_mode(app_mode=app_mode)
  # instead of .make_bundle(make_manifest_bundle, ...):
  #   ce.bundle = open(bundle_path, "rb")  (or a small helper)
  .deploy_bundle(activate=not draft)
  .save_deployed_info()
  .emit_task_log()

The only thing needed from inside the tarball is the app mode for validate_app_mode (api.py:1485). That can be read by pulling just the manifest.json member out of the tar (reusing the parsing in read_manifest_app_mode / read_manifest_file, bundle.py:818) — no full extraction required. make_bundle also sets self.deployment_name, so that one line would need to be factored out / called separately.

Suggested refactor

  • Factor the deployment_name assignment out of make_bundle (or add an open_bundle(path) executor method that sets self.bundle and the deployment name without re-bundling).
  • Add a helper to read manifest.json (and thus app mode + default title) directly from a tarball.
  • Wire up deploy bundle reusing the existing executor chain.

Caveats worth documenting / handling

  • Environment variables and secrets are not in the bundle — the target server must have them set (could be passed via -E KEY=value).
  • Dependencies are pinned in the manifest, so the target server needs a compatible Python/R version available.
  • Creates new content by default; updating existing content would still use --app-id.

Acceptance

  • rsconnect deploy bundle path/to/bundle.tar.gz --server ... --api-key ... deploys the bundle's content to the target server, uploading the downloaded tarball as-is (no re-bundling).
  • Standard deploy options (--name, --app-id, --title, -E, --new, etc.) are supported.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions