Skip to content

Commit 7e012ee

Browse files
Gkclaude
authored andcommitted
fix: resolve 6 CLI gaps from Argus integration tests (#89)
1. --worker: already worked, no change needed 2. --payload: already worked, no change needed 3. --on-failure: already worked, no change needed 4. key regenerate --yes: was returning HTTP 400 because API requires X-Confirm-Destructive: true header — now sends it 5. update command: did not exist — added with --name, --cron, --url, --payload, --description, --on-failure flags 6. --callback flag: added as alias for --url on both create and update 19 tests passing (3 new: callback alias, update help, update validation). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 958c9c3 commit 7e012ee

3 files changed

Lines changed: 75 additions & 2 deletions

File tree

cueapi/auth.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ def do_key_regenerate(
162162

163163
try:
164164
with CueAPIClient(api_key=api_key, profile=profile) as client:
165-
resp = client.post("/auth/key/regenerate")
165+
resp = client.post("/auth/key/regenerate", headers={"X-Confirm-Destructive": "true"})
166166
if resp.status_code != 200:
167167
echo_error(f"Failed to regenerate key (HTTP {resp.status_code})")
168168
return

cueapi/cli.py

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ def quickstart(ctx: click.Context) -> None:
7575
@click.option("--name", required=True, help="Cue name")
7676
@click.option("--cron", default=None, help="Cron expression for recurring cue")
7777
@click.option("--at", "at_time", default=None, help="ISO timestamp for one-time cue")
78-
@click.option("--url", default=None, help="Callback URL (not required with --worker)")
78+
@click.option("--url", "--callback", default=None, help="Callback URL (not required with --worker)")
7979
@click.option("--method", default="POST", help="HTTP method (default: POST)")
8080
@click.option("--timezone", "tz", default="UTC", help="Timezone (default: UTC)")
8181
@click.option("--payload", default=None, help="JSON payload string")
@@ -359,6 +359,57 @@ def delete(ctx: click.Context, cue_id: str, yes: bool) -> None:
359359
# --- Billing commands ---
360360

361361

362+
@main.command()
363+
@click.argument("cue_id")
364+
@click.option("--name", default=None, help="New cue name")
365+
@click.option("--cron", default=None, help="New cron expression")
366+
@click.option("--url", "--callback", "url", default=None, help="New callback URL")
367+
@click.option("--payload", default=None, help="New JSON payload")
368+
@click.option("--description", default=None, help="New description")
369+
@click.option("--on-failure", "on_failure", default=None, help="JSON on_failure config")
370+
@click.pass_context
371+
def update(ctx: click.Context, cue_id: str, name: Optional[str], cron: Optional[str],
372+
url: Optional[str], payload: Optional[str], description: Optional[str],
373+
on_failure: Optional[str]) -> None:
374+
"""Update an existing cue."""
375+
body: dict = {}
376+
if name:
377+
body["name"] = name
378+
if cron:
379+
body["schedule"] = {"type": "recurring", "cron": cron}
380+
if url:
381+
body["callback"] = {"url": url}
382+
if description:
383+
body["description"] = description
384+
if payload:
385+
try:
386+
body["payload"] = json.loads(payload)
387+
except json.JSONDecodeError:
388+
raise click.UsageError("--payload must be valid JSON")
389+
if on_failure:
390+
try:
391+
body["on_failure"] = json.loads(on_failure)
392+
except json.JSONDecodeError:
393+
raise click.UsageError("--on-failure must be valid JSON")
394+
395+
if not body:
396+
raise click.UsageError("Must specify at least one field to update.")
397+
398+
try:
399+
with CueAPIClient(api_key=ctx.obj.get("api_key"), profile=ctx.obj.get("profile")) as client:
400+
resp = client.patch(f"/cues/{cue_id}", json=body)
401+
if resp.status_code == 200:
402+
c = resp.json()
403+
echo_success(f"Updated: {cue_id} ({c['name']})")
404+
elif resp.status_code == 404:
405+
echo_error(f"Cue not found: {cue_id}")
406+
else:
407+
error = resp.json().get("detail", {}).get("error", {})
408+
echo_error(error.get("message", f"Failed (HTTP {resp.status_code})"))
409+
except click.ClickException as e:
410+
click.echo(str(e))
411+
412+
362413
@main.command()
363414
@click.pass_context
364415
def upgrade(ctx: click.Context) -> None:

tests/test_cli.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,28 @@ def test_create_on_failure_in_help():
6363
assert "--on-failure" in result.output
6464

6565

66+
def test_create_callback_alias():
67+
result = runner.invoke(main, ["create", "--help"])
68+
assert result.exit_code == 0
69+
assert "--callback" in result.output
70+
71+
72+
def test_update_help():
73+
result = runner.invoke(main, ["update", "--help"])
74+
assert result.exit_code == 0
75+
assert "--name" in result.output
76+
assert "--cron" in result.output
77+
assert "--callback" in result.output
78+
assert "--payload" in result.output
79+
assert "--on-failure" in result.output
80+
81+
82+
def test_update_requires_field():
83+
result = runner.invoke(main, ["update", "cue_test123"])
84+
assert result.exit_code != 0
85+
assert "must specify" in result.output.lower() or "at least one" in result.output.lower()
86+
87+
6688
def test_key_regenerate_help():
6789
result = runner.invoke(main, ["key", "regenerate", "--help"])
6890
assert result.exit_code == 0

0 commit comments

Comments
 (0)