Skip to content

feat(cube-cli): run and follow a dbt sync from the CLI - #11612

Merged
MikeNitsenko merged 3 commits into
masterfrom
codex/pr-11562-squashed
Aug 21, 2026
Merged

feat(cube-cli): run and follow a dbt sync from the CLI#11612
MikeNitsenko merged 3 commits into
masterfrom
codex/pr-11562-squashed

Conversation

@MikeNitsenko

@MikeNitsenko MikeNitsenko commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

This PR adds a Cube CLI workflow for running and monitoring dbt syncs in automation. It introduces cube dbt sync/status/result/cancel, wait and JSON output for CI, and branch cleanup commands while preserving existing optional --branch behavior.

Replaces #11562 with its intended final state on a fresh master base.

Summary

  • adds cube dbt sync/status/result/cancel, waiting, CI output, and branch cleanup
  • keeps existing optional --branch behavior compatible
  • validates empty branches only for new gate behavior (build-status --wait) and new commands
  • removes branch-name ref heuristics and follows the existing ref API contract
  • rejects empty dbt results, bounds result polling, handles oversized timeouts, and emits PowerShell-safe hints
  • removes global HTTP timeouts that would change existing commands

Validation

  • cargo +1.90.0 test
  • cargo +1.90.0 clippy --all-targets -- -D warnings
  • cargo +1.90.0 fmt --all --check

@github-actions github-actions Bot added rust Pull requests that update Rust code pr:community Contribution from Cube.js community members. labels Aug 21, 2026
@MikeNitsenko
MikeNitsenko marked this pull request as ready for review August 21, 2026 11:10
@MikeNitsenko
MikeNitsenko requested a review from keydunov as a code owner August 21, 2026 11:10
@claude

claude Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Claude finished @MikeNitsenko's task in 4m 7s —— View job


Review: solid work — 1 medium, 3 low. No blockers beyond the client.rs status-loss issue.

Full review — 4 inline comments, coverage notes, and what I checked
  • Gather context / read diff (git diff origin/master...HEAD)
  • Review wait.rs, util.rs, client.rs
  • Review commands/dbt.rs, deployments.rs, data_model.rs
  • Review docs (cli.mdx, dbt.mdx)
  • Check existing review threads (none open) & post findings

General observations

This is unusually careful code. A few things worth calling out as good:

  • wait::poll bounds the attempt, not just the gap between attempts. timeout_at(deadline, attempt()) plus the a_never_answering_attempt_still_times_out test closes the failure mode where a hung request outlives --timeout and hangs CI until the job timeout hours later. That's the bug most hand-rolled poll loops ship with.
  • Transient retries are a whitelist, not a blacklist. is_transient retries only 5xx/408/429/transport, so a verdict the poll closure itself reached (unknown sync id, "Branch is not active") fails immediately instead of being re-asked until the deadline. never_retries_a_verdict_the_attempt_reached pins it.
  • Consecutive rather than cumulative failure counting, with the streak message cleared on recovery — a_recovered_blip_is_not_blamed_for_a_later_timeout is exactly the assertion I'd have asked for.
  • only_the_listed_branch_arguments_refuse_an_empty_value is a genuinely good test: it walks the real clap tree and asserts both partitions, so neither a dropped value_parser nor a newly-declared --branch slips through unnoticed. The takes_a_value note about get_num_args() being unresolved pre-build is the kind of thing that's normally rediscovered the hard way.
  • shell_quote applied as a convention rather than an exemption list, including the PowerShell arm — and branch_or_placeholder returning padded names verbatim so the suggested delete-branch addresses the branch that actually exists. The reasoning in that doc comment is right.
  • one_line bounds as it goes rather than collapsing-then-truncating, with one_line_caps_a_body_of_any_size_or_shape covering both the many-small-tokens and no-whitespace-at-all shapes.
  • COMPLAINT_LIMIT vs REASON_LIMIT split (label is a dedupe key and must stay short; terminal reason is the whole message) is the right call and is tested.

Findings

# Severity Where Issue
1 Medium client.rs:338-343 res.text() failure now discards the HTTP status, breaking get_optional's 404 detection and the 401/403 messages
2 Low deployments.rs:297-305, dbt.rs:50-58 --timeout/--poll accepted and silently ignored without --wait
3 Low cli.mdx:425-428 Prune step runs under bash -e; a failed first delete-branch strands the sync branch
4 Low (nit) dbt.rs:365-379 --wait can exceed the user's --timeout by up to RESULT_FETCH_TIMEOUT (30s)

Details are in the inline comments. Only #1 is a behavior regression against master; the rest are UX/docs polish.

Security

Nothing concerning. Notable positives:

  • No new credential handling; auth stays on the existing Client path, including the one-shot 401 refresh.
  • shell_quote on every user-supplied value interpolated into a suggested command is the right posture — git check-ref-format permits #, $, ;, !, and these messages are read out of CI logs and pasted without rereading.
  • failure_detail caps response bodies at REASON_LIMIT before they reach a log, so a gateway HTML page can't bury the progress lines. Nothing matches on that text, so collapsing is free.
  • delete-branch correctly defaults --remove-on-upstream to off, so the connected provider is untouched unless asked.
  • branchName travels as a query parameter rather than a path segment because names contain slashes — right, and it means no path-injection surface.

Performance

No concerns. Backoff is capped at 60s and overflow-safe (checked_mulBACKOFF_CAP), MISSING_GRACE/IDLE_GRACE are measured in time rather than polls so --poll 1s can't silently shrink them to six seconds, and progress goes to stderr with label-change dedup so a 15-minute wait produces a handful of lines.

Testing

Coverage is strong for new code — wait.rs, util.rs, client.rs's failure_detail, and dbt.rs's status_label/available_result/wait_json all have focused tests, several written specifically against the failure they replaced. Gaps I noticed, none blocking:

  • No test for the client.rs body-read-failure path (finding ReferenceError: self is not defined - Issue with whatwg-fetch when using the core lib with Node.js #1) — the regression is invisible to the suite today.
  • wait_for_sync's MISSING_GRACE and wait_for_build's IDLE_GRACE expiry are untested. Both are Instant-based inside a closure, so a test would need injectable time; a cheap partial version would extract the "has the grace expired" decision into a function taking elapsed: Duration.
  • print_result uses output::items on generatedFiles; a non-array value would render as one file. Almost certainly not reachable, but untested.

I could not run cargo test / clippy — cargo isn't in this job's allowed tools, so I reviewed statically. The PR body reports all three passing on 1.90.0.

Documentation

docs-mintlify is the right place, docs.json needs no change (no new pages), anchors resolve (#dbt-sync, #dbt-sync-as-a-ci-test-gate), and --remove-on-upstream / --keep-branch / exit-dev-mode all exist as documented. The <Warning> about $DEV being empty when jq exits 0 without pipefail is a good catch to have written down. Only finding #3 above.

• branch `codex/pr-11562-squashed`

Comment thread rust/cube-cli/src/client.rs Outdated
Comment thread rust/cube-cli/src/commands/deployments.rs Outdated
Comment thread docs-mintlify/reference/cli.mdx Outdated
Comment thread rust/cube-cli/src/commands/dbt.rs
@claude

claude Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Claude finished @MikeNitsenko's task in 1m 31s —— View job


Re-review of 8ac5553: all 4 prior findings addressed. No new issues — LGTM.

Full re-review — what changed, verification of each fix, and what I checked
  • List existing review threads (4 prior findings — all already resolved by the author)
  • Review the follow-up commit 8ac5553 against my earlier findings
  • Re-scan the full diff for anything new
  • Post updated review

What changed since my last pass

8ac5553 touches 5 files, +45/−13, and is entirely review feedback. Each of my four findings is fixed:

# Prior finding Fix Verdict
1 (Medium) client.rs — body-read failure discarded the HTTP status res.text().await.unwrap_or_default() restored, with a comment naming the three callers that branch on status (404 handling, transient retry, one-shot 401 refresh) ✅ Correct — this was the only behavior regression against master, and it's gone
2 (Low) --timeout/--poll silently ignored without --wait requires = "wait" on all six args across dbt sync, dbt status, deployments build-status ✅ Correct, and went one better than I suggested
3 (Low) Prune step stranded the sync branch under bash -e rc=0 / || rc=$? / exit $rc ✅ Correct — cmd || rc=$? is exempt from -e as the left side of a || list, so both deletes always run and a failure of either still fails the step
4 (Nit) --wait can exceed --timeout by RESULT_FETCH_TIMEOUT dbt sync --timeout help now reads "Give up waiting for the sync after this long; reading its result may take 30s more" ✅ Took the documentation option, which is the right trade — subtracting elapsed time would have given the final request a budget of zero exactly when the sync ran long

Notes on the fixes

On #2, the author extended requires to dbt sync too, which I'd explicitly exempted. That's the better call: dbt sync --timeout 1h without --wait is just as inert as the status case, and I was wrong to carve it out. No compatibility concern — --timeout/--poll are new on all three subcommands in this PR, so nothing that parsed on master stops parsing.

The clap requires-with-default_value interaction is the thing that would bite here, and explicit_wait_options_require_wait (util.rs:530) pins both halves: three explicit-without---wait invocations must fail with --wait named in the message, and three bare invocations must still parse despite carrying defaults. Asserting on the error text rather than just is_err() is what makes the first loop meaningful — a required-positional error would otherwise pass it. The test reuses the crate::Cli::try_parse_from pattern already established by only_the_listed_branch_arguments_refuse_an_empty_value, so it exercises the real command tree rather than a hand-built parser.

validate_build_status_args is unaffected — it polices --branch "" with --wait, a different pairing, and clap now handles the timeout/poll case declaratively before that function is reached.

Standing observations (unchanged, no action)

The strengths from my first pass still hold and nothing in this commit weakened them: wait::poll bounding the attempt rather than the gap, the transient-retry whitelist, consecutive-not-cumulative failure counting, shell_quote as a convention rather than an exemption list, and one_line bounding as it goes.

The testing gaps I noted remain, none blocking:

  • wait_for_sync's MISSING_GRACE and wait_for_build's IDLE_GRACE expiry are untested (both Instant-based inside closures — would need injectable time, or extraction of the "has the grace expired" decision into a function taking elapsed: Duration).
  • No test for the client.rs body-read-failure path. Finding ReferenceError: self is not defined - Issue with whatwg-fetch when using the core lib with Node.js #1 is fixed, but the fix is still invisible to the suite, so the same regression could return.
  • print_result's output::items on a non-array generatedFiles. Almost certainly unreachable.

Verification caveat

cargo is not in this job's allowed tools, so I reviewed statically and could not run cargo test / clippy / fmt myself. The reasoning above about clap's requires-vs-default_value behavior rests on the new test asserting it, not on my having executed it. The PR body reports all three passing on 1.90.0.

All four of my earlier threads were already resolved before this pass, so nothing needed resolving and no inline comments were posted — there is nothing left outstanding to re-affirm.

• branch `codex/pr-11562-squashed`

@mintlify

mintlify Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
cubed3 🟢 Ready View Preview Aug 21, 2026, 11:39 AM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@MikeNitsenko
MikeNitsenko merged commit f5ee250 into master Aug 21, 2026
18 checks passed
@MikeNitsenko
MikeNitsenko deleted the codex/pr-11562-squashed branch August 21, 2026 21:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr:community Contribution from Cube.js community members. rust Pull requests that update Rust code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants