feat(sync): opt-in sync of shared SQL workspaces in pull, diff, push and clone (CLI-25) - #815
Conversation
…and clone (CLI-25)
keboola-pr-reviewer-bot
left a comment
There was a problem hiding this comment.
reviewer could not complete: opencode exited 1: (no stderr — check the reviewer logs for the trace summary)
Retry with @keboola-pr-reviewer review once the underlying issue clears.
|
@keboola-pr-reviewer review |
keboola-pr-reviewer-bot
left a comment
There was a problem hiding this comment.
reviewer could not complete: opencode exited 1: (no stderr — check the reviewer logs for the trace summary)
Retry with @keboola-pr-reviewer review once the underlying issue clears.
zajca
left a comment
There was a problem hiding this comment.
Actionable findings from the automated review.
…with a test (CLI-25)
zajca
left a comment
There was a problem hiding this comment.
No actionable findings were found by the automated review.
This PR is based on #814, which is based on #811, and shows only its own commit. Merge #811, then #814, then this PR, each with a merge commit. The order matters: this PR deletes workspaces only through the
--forcegate that #811 adds.What was wrong
sync pull,diff,pushandclonealways skipped workspaces (keboola.sandboxesinALWAYS_IGNORED_COMPONENTS). A reference project copied withsync clonehad no workspaces in the copy.What changed
syncWorkspaces, whichsync init --with-workspacessets. The manifest has the key only while it is on, so other trees do not change. AnignoredComponentsentry forkeboola.sandboxesstill wins, andkeboola.mcp-server-toolstays ignored.runtime.shared: trueand noparameters.id. This is the rule of the Keboola UI for a workspace that all users see, and the old Keboola CLI (kbc) uses the sameparameters.idtest for SQL. A workspace fromkbagent workspace create(not shared), a Python or R workspace and a legacy sandbox stay out. A workspace that is already tracked stays tracked when somebody makes it private, so push does not create it again.backendSizechanges, because the change applies only to a new session.sync push --force, as for every configuration after fix(sync): push deletes only with --force and skips remote-deleted configs (#792 G, H) #811. For a workspace, push first deletes the SQL editor sessions of that workspace, also the sessions of other users, and then the configuration, likekbc remote workspace delete. A deleted session also drops its Snowflake or BigQuery workspace, and that cannot be undone. Push keeps the configuration and the manifest entry when the session list fails or is not a list, when a session delete fails, or when the configuration has aparameters.id. When a session delete or the final configuration delete fails, the error names the sessions already deleted. A 404 on a session delete counts as deleted.sync push --dry-run --forcelists the sessions that push would delete, and a plain push that holds back a workspace delete says that--forcealso deletes the sessions.sync push --forcehas the permission classdestructive(FLAG_ESCALATIONS), so--deny-destructiveand a policy that deniescli:destructiveblock it.sync clonecreates the workspace configurations and gives a warning for each input table that does not exist in the target, because clone creates buckets but no tables. The link re-pointing from fix(sync): remap shared-code, orchestrator and schedule links, add clone warnings (CLI-24) #814 also covers the shared-code and variables links of a workspace.ignored, but keeps a workspace with local edits and reports it as skipped. Only--theirsremoves it.client/editor.py, hosteditor.<stack>) with the session list and delete. It never asks for credentials.Behavior changes
sync push --forceis now checked as its own operation,sync.push --force, with the classdestructive. This applies to every tree, also withoutsyncWorkspaces. A pipeline that runssync push --forcestops with exit code 6 under these policies:cli:destructive, or--deny-destructive,--mode deny) that names onlysync.push,cli:writeand allowssync.push.To allow a forced push, add
--allow "sync.push --force"or a glob such assync.*.permissions-workflow.mdandgotchas.mdsay this, and a test pins each policy shape. The escalation is static, likeauth.logout --remove-projects, so a policy decides before any API call and does not depend on what the push would delete.Tests
tests/test_sync_workspaces.pyruns the real pull, diff, push and clone on the filesystem with clients built fromMagicMock(spec=KeboolaClient), and checks the full list of client calls. It covers the opt-in on and off, the scope rule, no diff after pull, config-only create and update, the size warning, a plain push that holds back the delete,--forcewith sessions deleted before the config, listing and delete failures, a 404, the refusal forparameters.id, the dry-run preview, the clone warning, dev branches and the Editor client errors.tests/test_sync_clone_links.pychecks that a cloned workspace gets its new shared-code and variables links.make checkpasses.Not checked against a live project yet. Before the merge, please run this once on a dev stack: create a shared SQL workspace and open it once,
sync pull, delete its directory,sync push --dry-run --force,sync push --force, then check that the sessions are gone and thatworkspace list --orphanedis empty. Also check that the UI shows a workspace created by push with the correct type and opens it.Docs:
gotchas.md(since vNEXT),sync-workflow.md,commands-reference.md,permissions-workflow.md,keboola-expert.md,context.py,CLAUDE.md,docs/TUTORIAL.md. No version bump, no changelog entry.Fixes CLI-25