Skip to content

feat: verify deployment on a draft, activate on success#805

Open
nealrichardson wants to merge 5 commits into
mainfrom
claude-issue-769
Open

feat: verify deployment on a draft, activate on success#805
nealrichardson wants to merge 5 commits into
mainfrom
claude-issue-769

Conversation

@nealrichardson

@nealrichardson nealrichardson commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Closes #769. Also fixes #768.

What

Makes verify-before-activate the default for rsconnect deploy, on Connect servers that support it:

  1. Deploy as a draft — the new bundle is deployed with activate: false.
  2. Verify the draftaccess_content hits the draft bundle's preview URL (/content/<guid>/_bundle<id>/), which cold-starts the process, so a non-5xx response confirms the content actually runs.
  3. Activate on success — a second POST .../deploy with activate: true (the "Activate Draft" button's behavior). If verification fails, the bundle is left as a draft and the previously-active bundle keeps serving, so a broken build never becomes the active version.

This also fixes #768: --draft now verifies the draft bundle rather than the currently-active content.

Flag behavior (Connect >= 2025.06.0)

flags deploy verify activate
(none) draft draft preview URL yes, on success
--draft draft draft preview URL no
--no-verify active immediate

Version gating

Connect added the activate field on the deploy endpoint in 2025.06.0; older servers reject the unknown field. So the draft-first flow is gated on server version:

  • Connect >= 2025.06.0: the flow above.
  • Older Connect / shinyapps.io: deploy and activate in one step (no activate field sent) and verify the active content — i.e. the pre-PR behavior. --draft against these servers is unsupported (it cannot be expressed without the activate field).

Changes

  • api.py:
    • access_content takes an optional bundle_id and accesses the draft preview URL when given one.
    • verify_deployment targets the draft bundle when one was deployed (not yet active), otherwise the active content.
    • new activate_deployment method (re-issues the deploy with activate: true).
    • bundle_id threaded into the deploy result.
    • server_supports_draft_deploy(version) helper + RSConnectExecutor.supports_verify_before_activate (cached) and should_deploy_as_draft(...) to centralize the gating decision.
    • fixes a pre-existing //content double-slash in the access path.
  • main.py: deploy call sites use should_deploy_as_draft / supports_verify_before_activate; --draft / --no-verify help text updated.
  • tests/test_main.py:
    • unit tests for the draft -> verify -> activate sequence and for the old-server fallback (no activate field, single deploy, verify active).
    • two live-Connect integration tests (run via posit-dev/with-connect, gated to Connect >= 2025.06.0) that fail without these changes:

🤖 Generated with Claude Code

nealrichardson and others added 3 commits June 29, 2026 10:50
Deploy commands now deploy the new bundle as a draft (activate=false),
verify it by accessing its preview URL, and only activate it once the
verification succeeds. If verification fails, the bundle is left as a
draft and the previously-active bundle keeps serving, so a broken build
never becomes the active version.

This also fixes #768: --draft now verifies the draft bundle rather than
the currently-active content. --no-verify retains the old behavior of
activating immediately without verification.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
dirname("/__api__") returns "/", so joining it with "/content/..."
produced a "//content/..." path. Connect normalizes it, but it is sloppy
and made the verification request URL awkward to register in tests. Strip
the trailing slash from the base so root-hosted and path-prefixed servers
both produce a clean single-slash path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add two live-Connect integration tests (run via posit-dev/with-connect)
that exercise the verify-before-activate guarantees and are expected to
fail without the changes on this branch:

- test_default_deploy_does_not_activate_broken_bundle (#769): a broken
  redeploy fails and leaves the previously-active working bundle serving;
  without the change the broken bundle is activated before verification.
- test_draft_deploy_verifies_the_draft_not_the_active_bundle (#768):
  deploying a broken draft fails verification; without the change --draft
  verified the still-good active content and reported success.

Both reuse the existing flask / flask-bad fixtures (flask-bad builds fine
but raises at startup).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown
PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://posit-dev.github.io/rsconnect-python/pr-preview/pr-805/

Built to branch gh-pages at 2026-06-29 18:47 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown

☂️ Python Coverage

current status: ✅

Overall Coverage

Lines Covered Coverage Threshold Status
7518 6177 82% 0% 🟢

New Files

No new covered files...

Modified Files

File Coverage Status
rsconnect/api.py 81% 🟢
rsconnect/main.py 80% 🟢
TOTAL 80% 🟢

updated for commit: d3f57db by action🐍

nealrichardson and others added 2 commits June 29, 2026 11:41
Connect added the `activate` field on the deploy endpoint in 2025.06.0;
older servers reject the unknown field, which broke every deploy against
them once verify-before-activate became the default. Gate the draft-first
flow on server version: on Connect >= 2025.06.0 we deploy a draft, verify
it, and activate on success; on older servers (and shinyapps.io) we deploy
and activate in one step and verify the active content, as before.

Add a unit test for the fallback path on an unsupported server, and bump
the two live integration tests to require Connect 2025.06.0 since they
assert the verify-before-activate behavior.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
should_deploy_as_draft() returned True for --draft regardless of server
support, so --draft against Connect < 2025.06.0 still sent activate:false
and failed with a cryptic "unknown field" error. Raise a clear
RSConnectException instead; silently downgrading to a non-draft deploy
would activate the bundle, the opposite of --draft's intent. Add a unit
test for --draft on an unsupported server.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: verify deployment on a draft, activate on success bug: verify_deployment doesn't verify a draft

1 participant