fix(cli): preserve user drafts on sync push and permissioned-as#9381
Conversation
CLI deploys (sync push, set-permissioned-as) went through the same create/update endpoints as a UI "deploy from draft", which delete the draft at that path. That silently wiped teammates' in-progress drafts on every push. Add a transient skip_draft_deletion deploy flag (mirroring deployment_message) that the CLI sets; the backend then skips the DELETE FROM draft for scripts, flows, and apps. UI deploys are unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Deploying windmill with
|
| Latest commit: |
b21cde4
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://95fd2e37.windmill.pages.dev |
| Branch Preview URL: | https://fix-sync-draft-override.windmill.pages.dev |
|
Claude finished @hugocasa's task in 5m 37s —— View job cc @hugocasa Mergeable, but should ideally address nits: no automated regression test for the draft‑preservation behavior; CLI scope is slightly broader than the PR title (every script/flow/app push, not only SummaryThe fix is well‑scoped and correct. I verified the completeness and routing claims in the description against the actual code — they all hold up. Completeness of
The 8 untouched sites are all correctly left alone — I read each one: Routing claims verified:
Correctness of the exclusions:
No coverage gap for variables/resources: only FindingsP2 — CLI scope is broader than the PR title. The flag is set in the shared No P0 or P1 issues found. AGENTS.md complianceNo violations. The change follows the existing Test coverageThis is a backend behavior change to DB‑mutating API handlers. Per the repo's review policy, modified API handlers / DB access should ideally have integration tests. The only test change here ( There's a clean pattern to mirror: Frontend: openapi regen touches Manual verification still worth doing before merge (the two unchecked test‑plan boxes): in the editor, perform a UI "deploy from draft" for a script/flow/app and confirm the unsaved‑changes marker still clears (the default‑off path must be unchanged); and run a |
Pi ReviewGood to merge SummaryThis PR adds a FindingsNo blocking issues or nits identified. Mechanics walkthrough
No false positives from
|
Codex ReviewGood to merge No issues found. Checked the backend deploy paths, CLI call sites, OpenAPI shape, and AGENTS.md compliance. Test coverageBackend changes affect API deploy handlers and DB draft deletion behavior. I do not see an automated regression/integration test for preserving drafts on CLI deploys, so the manual scenarios in the PR body remain the main coverage. Manual verification should still cover UI deploy-from-draft for script, flow, and app: deploying from the editor without |
Summary
wmill sync push(and theset-permissioned-ascommands) deploy scripts/flows/apps through the same create/update API endpoints the UI "Deploy" button uses. Every one of those deploy paths runsDELETE FROM draftfor the item's path inside the transaction. That's correct for a UI deploy-from-draft (the draft becomes the deployed version, so the "unsaved changes" marker is cleared) — but when a CLI/git-sync push touches a path, it silently destroys whatever in-progress draft a teammate has there, even though the push had nothing to do with that draft.This fix makes CLI deploys preserve drafts while leaving UI deploys unchanged.
Approach
Mirror the existing
deployment_messagepattern: a transient, deploy-control body fieldskip_draft_deletionthat the CLI sets totrueon its deploy paths. When set, the backend skips theDELETE FROM draft; the deploy itself proceeds normally. UI deploys never send it (defaults tofalse), so their behavior is identical to before.Changes
Backend
skip_draft_deletion: Option<bool>toNewScript,NewFlow,CreateApp,EditApp(#[serde(default, skip_serializing_if = "Option::is_none")]).DELETE FROM draftsites:create_script_internal(both parent/no-parent branches),create_flow,update_flow,create_app_internal,update_app_internal. The script snapshot and raw-app endpoints route through these same internal functions, so they inherit the guard.NewScriptHashimpl (it must not affect version identity) and bound it to_in the no-op drift-guard destructure (caller intent, not script state).delete_script/delete_flow/delete_app, bulk delete) draft deletions are left untouched.CLI
skip_draft_deletion: trueon the sync push helpers (createScript,pushFlow,pushApp,pushRawApp) and on theset-permissioned-asredeploys for script/flow/app.openapi.yaml
NewScriptcomponent.cli/genandfrontend/src/lib/genare gitignored and regenerated from the spec at build time.Test plan
Verified end-to-end against a running backend (script, flow, and app each with a saved draft):
skip_draft_deletion=true→ draft survives (count 1), deploy succeedswmill sync push🤖 Generated with Claude Code