Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cueapi/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ def do_key_regenerate(

try:
with CueAPIClient(api_key=api_key, profile=profile) as client:
resp = client.post("/auth/key/regenerate")
resp = client.post("/auth/key/regenerate", headers={"X-Confirm-Destructive": "true"})
if resp.status_code != 200:
echo_error(f"Failed to regenerate key (HTTP {resp.status_code})")
return
Expand Down
53 changes: 52 additions & 1 deletion cueapi/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ def quickstart(ctx: click.Context) -> None:
@click.option("--name", required=True, help="Cue name")
@click.option("--cron", default=None, help="Cron expression for recurring cue")
@click.option("--at", "at_time", default=None, help="ISO timestamp for one-time cue")
@click.option("--url", default=None, help="Callback URL (not required with --worker)")
@click.option("--url", "--callback", default=None, help="Callback URL (not required with --worker)")
@click.option("--method", default="POST", help="HTTP method (default: POST)")
@click.option("--timezone", "tz", default="UTC", help="Timezone (default: UTC)")
@click.option("--payload", default=None, help="JSON payload string")
Expand Down Expand Up @@ -359,6 +359,57 @@ def delete(ctx: click.Context, cue_id: str, yes: bool) -> None:
# --- Billing commands ---


@main.command()
@click.argument("cue_id")
@click.option("--name", default=None, help="New cue name")
@click.option("--cron", default=None, help="New cron expression")
@click.option("--url", "--callback", "url", default=None, help="New callback URL")
@click.option("--payload", default=None, help="New JSON payload")
@click.option("--description", default=None, help="New description")
@click.option("--on-failure", "on_failure", default=None, help="JSON on_failure config")
@click.pass_context
def update(ctx: click.Context, cue_id: str, name: Optional[str], cron: Optional[str],
url: Optional[str], payload: Optional[str], description: Optional[str],
on_failure: Optional[str]) -> None:
"""Update an existing cue."""
body: dict = {}
if name:
body["name"] = name
if cron:
body["schedule"] = {"type": "recurring", "cron": cron}
if url:
body["callback"] = {"url": url}
if description:
body["description"] = description
if payload:
try:
body["payload"] = json.loads(payload)
except json.JSONDecodeError:
raise click.UsageError("--payload must be valid JSON")
if on_failure:
try:
body["on_failure"] = json.loads(on_failure)
except json.JSONDecodeError:
raise click.UsageError("--on-failure must be valid JSON")

if not body:
raise click.UsageError("Must specify at least one field to update.")

try:
with CueAPIClient(api_key=ctx.obj.get("api_key"), profile=ctx.obj.get("profile")) as client:
resp = client.patch(f"/cues/{cue_id}", json=body)
if resp.status_code == 200:
c = resp.json()
echo_success(f"Updated: {cue_id} ({c['name']})")
elif resp.status_code == 404:
echo_error(f"Cue not found: {cue_id}")
else:
error = resp.json().get("detail", {}).get("error", {})
echo_error(error.get("message", f"Failed (HTTP {resp.status_code})"))
except click.ClickException as e:
click.echo(str(e))


@main.command()
@click.pass_context
def upgrade(ctx: click.Context) -> None:
Expand Down
22 changes: 22 additions & 0 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,28 @@ def test_create_on_failure_in_help():
assert "--on-failure" in result.output


def test_create_callback_alias():
result = runner.invoke(main, ["create", "--help"])
assert result.exit_code == 0
assert "--callback" in result.output


def test_update_help():
result = runner.invoke(main, ["update", "--help"])
assert result.exit_code == 0
assert "--name" in result.output
assert "--cron" in result.output
assert "--callback" in result.output
assert "--payload" in result.output
assert "--on-failure" in result.output


def test_update_requires_field():
result = runner.invoke(main, ["update", "cue_test123"])
assert result.exit_code != 0
assert "must specify" in result.output.lower() or "at least one" in result.output.lower()


def test_key_regenerate_help():
result = runner.invoke(main, ["key", "regenerate", "--help"])
assert result.exit_code == 0
Expand Down
Loading