mirror of
https://github.com/simonw/dclient.git
synced 2026-07-24 18:04:33 +02:00
Add instances command, improve error messages with actionable hints
Add "dclient instances" command to list known instances from config, with --json support. Improve "No instance specified" and "No database specified" error messages to show the exact commands needed to fix the problem. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
3f3221fdd3
commit
7b3a15027e
2 changed files with 86 additions and 2 deletions
|
|
@ -60,7 +60,10 @@ def _resolve_instance(instance, config_file):
|
|||
if env_url:
|
||||
return env_url.rstrip("/")
|
||||
raise click.ClickException(
|
||||
"No instance specified. Use -i, set a default instance, or set DATASETTE_URL."
|
||||
"No instance specified. Use -i <url-or-alias>, or configure a default:\n\n"
|
||||
" dclient alias add <name> <url>\n"
|
||||
" dclient alias default <name>\n\n"
|
||||
"Or set the DATASETTE_URL environment variable."
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -81,7 +84,9 @@ def _resolve_database(database, instance_alias, config_file):
|
|||
if env_db:
|
||||
return env_db
|
||||
raise click.ClickException(
|
||||
"No database specified. Use -d, set a default database, or set DATASETTE_DATABASE."
|
||||
"No database specified. Use -d <name>, or configure a default:\n\n"
|
||||
" dclient alias default-db <alias> <database>\n\n"
|
||||
"Or set the DATASETTE_DATABASE environment variable."
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -642,6 +647,31 @@ def default_query(sql, instance, database, token, verbose):
|
|||
click.echo(json.dumps(response.json()["rows"], indent=2))
|
||||
|
||||
|
||||
@cli.command()
|
||||
@click.option("--json", "_json", is_flag=True, help="Output raw JSON")
|
||||
def instances(_json):
|
||||
"""
|
||||
List known instances from the config
|
||||
|
||||
Example usage:
|
||||
|
||||
\b
|
||||
dclient instances
|
||||
dclient instances --json
|
||||
"""
|
||||
config_file = get_config_dir() / "config.json"
|
||||
config = _load_config(config_file)
|
||||
inst_map = config.get("instances", {})
|
||||
default = config.get("default_instance")
|
||||
if _json:
|
||||
click.echo(json.dumps(config, indent=2))
|
||||
else:
|
||||
for name, inst in inst_map.items():
|
||||
marker = "* " if name == default else " "
|
||||
db_info = f" (db: {inst['default_database']})" if inst.get("default_database") else ""
|
||||
click.echo(f"{marker}{name} = {inst['url']}{db_info}")
|
||||
|
||||
|
||||
# -- alias command group --
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -536,3 +536,57 @@ def test_get_command(httpx_mock, mocker, tmpdir):
|
|||
assert data == {"hello": "world"}
|
||||
request = httpx_mock.get_request()
|
||||
assert request.url.path == "/-/plugins.json"
|
||||
|
||||
|
||||
# -- instances command --
|
||||
|
||||
|
||||
def test_instances_plain(mocker, tmpdir):
|
||||
config_dir = pathlib.Path(tmpdir)
|
||||
mocker.patch("dclient.cli.get_config_dir", return_value=config_dir)
|
||||
(config_dir / "config.json").write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"default_instance": "prod",
|
||||
"instances": {
|
||||
"prod": {"url": "https://prod.example.com", "default_database": "main"},
|
||||
"staging": {"url": "https://staging.example.com", "default_database": None},
|
||||
},
|
||||
}
|
||||
)
|
||||
)
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(cli, ["instances"])
|
||||
assert result.exit_code == 0
|
||||
assert "* prod = https://prod.example.com (db: main)" in result.output
|
||||
assert " staging = https://staging.example.com" in result.output
|
||||
|
||||
|
||||
def test_instances_json(mocker, tmpdir):
|
||||
config_dir = pathlib.Path(tmpdir)
|
||||
mocker.patch("dclient.cli.get_config_dir", return_value=config_dir)
|
||||
(config_dir / "config.json").write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"default_instance": "prod",
|
||||
"instances": {
|
||||
"prod": {"url": "https://prod.example.com", "default_database": "main"},
|
||||
},
|
||||
}
|
||||
)
|
||||
)
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(cli, ["instances", "--json"])
|
||||
assert result.exit_code == 0
|
||||
data = json.loads(result.output)
|
||||
assert "prod" in data["instances"]
|
||||
assert data["default_instance"] == "prod"
|
||||
|
||||
|
||||
def test_instances_empty(mocker, tmpdir):
|
||||
config_dir = pathlib.Path(tmpdir)
|
||||
mocker.patch("dclient.cli.get_config_dir", return_value=config_dir)
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(cli, ["instances"])
|
||||
assert result.exit_code == 0
|
||||
assert result.output.strip() == ""
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue