Skip to content

Add --json flag, restructure CLI modules, server --version flag, and table output#82

Merged
sdairs merged 15 commits intomainfrom
issue-81-json-output-local-commands
Apr 5, 2026
Merged

Add --json flag, restructure CLI modules, server --version flag, and table output#82
sdairs merged 15 commits intomainfrom
issue-81-json-output-local-commands

Conversation

@sdairs
Copy link
Copy Markdown
Collaborator

@sdairs sdairs commented Apr 4, 2026

Summary

--json output for local commands (closes #81)

  • Adds --json flag to all local subcommands (list, which, install, use, remove, init, server start/list/stop/stop-all/remove)
  • Structured output types implement both Serialize (for JSON) and Display (for human-readable text)
  • Follows the same --json pattern used by cloud commands (LocalArgs wrapper with global = true)
  • local client is excluded since it exec()s into clickhouse-client
  • --json and --foreground are mutually exclusive on server start

Restructure CLI into local/ and cloud/ modules (closes #86)

  • Moves local command definitions and handlers from src/cli.rs and src/main.rs into src/local/cli.rs and src/local/mod.rs
  • Moves cloud command definitions into src/cloud/cli.rs
  • Moves src/local_output.rs to src/local/output.rs and src/server.rs to src/local/server.rs
  • src/main.rs now just dispatches to local::run() and cloud::run()

--version flag for local server start (closes #83)

  • Adds --version (-v) flag accepting the same version specs as install/use (stable, lts, latest, 25.12, etc.)
  • Installs the version if needed, starts the server with it, but does not change the default version
  • Fails fast on server name collision before downloading
  • ensure_installed() returns existing versions silently instead of erroring

Version resolution fix

  • find_version_by_refs now falls back to any tagged version (e.g. -new) when no -stable or -lts tag exists, fixing resolution of newer versions like 26.4

Table output for list commands (closes #87)

  • Adds the tabled crate for formatted table output (rounded style) in all list commands
  • Local commands: local list, local list --remote, local server list
  • Cloud commands: cloud org list, cloud service list, cloud backup list, cloud member list, cloud invitation list, cloud key list, cloud activity list, cloud org usage
  • Empty-state outputs and JSON output are unaffected

Fix ETXTBSY on version install

  • Explicitly flush and close the async file handle after downloading a binary, preventing "Text file busy" (os error 26) when detecting the version immediately after download

Test plan

  • 34 unit tests for JSON serialization and Display formatting of all output types
  • 13 tests for version ref parsing (stable/lts preference, unknown suffix fallback, edge cases)
  • Test for --json and --foreground mutual exclusivity
  • Full test suite passes (247 tests), cargo clippy clean
  • Manual: local server start --version stable starts server without changing default
  • Manual: local server start --version 26.4 resolves and starts correctly
  • Manual: local --json server start --foreground errors immediately
  • Manual: local server list renders as a table with columns
  • CI install tests pass on Ubuntu and macOS

Closes #81, closes #83, closes #87, closes #86

🤖 Generated with Claude Code

sdairs and others added 2 commits April 4, 2026 16:59
Introduces src/local_output.rs with serializable output types for all
local commands (list, which, install, use, remove, init, server *).
Each type implements both Serialize (for --json) and Display (for
human-readable output). Includes 34 unit tests covering JSON
serialization and Display formatting.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds LocalArgs wrapper struct with global --json flag (matching the
CloudArgs pattern) and threads it through every local command handler.
Each handler now builds a structured output type and uses print_output()
to emit either JSON or human-readable text.

Closes #81

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@sdairs sdairs requested a review from iskakaushik as a code owner April 4, 2026 16:05
@sdairs sdairs temporarily deployed to cloud-integration April 4, 2026 16:05 — with GitHub Actions Inactive
sdairs and others added 7 commits April 4, 2026 17:52
Moves local command code into src/local/ (cli.rs, mod.rs, output.rs,
server.rs) and cloud CLI types into src/cloud/cli.rs. Root cli.rs is
now a thin shell (~136 lines) with just Cli, Commands, SkillsArgs, and
re-exports. Local changes no longer require touching shared files.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Allows starting a server with a specific ClickHouse version without
changing the default version. The flag accepts the same version specs
as install/use (stable, lts, latest, 25.12, etc.) and installs the
version if needed.

Closes #83

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…n name collision

- Add `ensure_installed()` that returns existing version instead of
  erroring when already installed (unlike `install_resolved` which is
  meant for the explicit `install` command)
- Move server name collision check before version resolution so we
  don't download a version only to fail on a name conflict

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The GitHub matching-refs fallback in find_version_by_refs only accepted
tags with -stable or -lts suffixes. Newer versions (e.g. 26.4) may
only have tags like -new, causing "No matching version found" errors
even though the version exists. Now falls back to any tagged version
when no stable/lts tag is found.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extract parse_version_refs() and parse_exact_channel() from their
network-dependent callers so the ref-parsing logic can be tested
in isolation. Adds 13 tests covering:

- Stable/LTS tag matching
- Fallback to unknown suffixes (e.g. -new)
- Preference ordering (stable > unknown)
- Edge cases: empty refs, missing dashes, non-tag refs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
These flags are mutually exclusive — foreground streams server output
directly while --json expects structured output on completion.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@sdairs sdairs temporarily deployed to cloud-integration April 4, 2026 18:11 — with GitHub Actions Inactive
@sdairs sdairs changed the title Support --json output for local commands Add --json flag, restructure CLI modules, and add server --version flag Apr 4, 2026
@sdairs sdairs temporarily deployed to cloud-integration April 4, 2026 18:12 — with GitHub Actions Inactive
@sdairs sdairs temporarily deployed to cloud-integration April 4, 2026 18:14 — with GitHub Actions Inactive
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@sdairs sdairs temporarily deployed to cloud-integration April 4, 2026 18:21 — with GitHub Actions Inactive
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@sdairs sdairs temporarily deployed to cloud-integration April 4, 2026 18:43 — with GitHub Actions Inactive
sdairs and others added 4 commits April 4, 2026 20:12
Replace plain-text list formatting with tabled tables (rounded style) for
all list commands: local list, local list --remote, local server list,
cloud org list, cloud service list, cloud backup list, cloud member list,
cloud invitation list, cloud key list, cloud activity list, and cloud
org usage.

Closes #87

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The async file handle from tokio::fs::File was not explicitly flushed
or closed before returning from download_url. On macOS, this could leave
the file descriptor open for writing when detect_binary_version tried to
exec the binary, causing "Text file busy" (ETXTBSY / os error 26).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The test was matching "^  [0-9]" which assumed the old indented list
format. With tabled output, version numbers are inside table cells.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…output

Use tabled for human-readable list output
@sdairs sdairs temporarily deployed to cloud-integration April 4, 2026 20:19 — with GitHub Actions Inactive
@sdairs sdairs changed the title Add --json flag, restructure CLI modules, and add server --version flag Add --json flag, restructure CLI modules, server --version flag, and table output Apr 4, 2026
@sdairs sdairs merged commit dd65357 into main Apr 5, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants