feat(cli): close E2E To-Do CLI gaps (B1, B2, F2, F1, F3)
A CLI-only walkthrough (E2E_TODO_REPORT.md) found two control-plane
operations with no `pic` command — every CLI-created app 404'd until it
claimed a domain, and external SSE feeds needed a raw topic-registration
call — plus several friction points. All admin APIs already existed; this
adds thin wrappers mirroring `routes`/`triggers`:
- B1: `pic apps domains {ls,add,rm}` over apps/{id}/domains.
- B2: `pic topics {ls,create,update,rm}` over apps/{id}/topics, and a
triggers help note distinguishing a pubsub trigger from topic
registration.
- F2: `pic users {ls,show,reset-password,revoke-sessions}` over the app
end-user admin surface (read + the two admin actions; create/invitations
deferred).
- F1: `apps create` and `deploy` now honor `--output json`, emitting the
created object so scripts can capture the id.
- F3: non-interactive login via `--username` + `--password-stdin` (inline
passwords still rejected, mirroring the `--token` rule).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -10,7 +10,7 @@ use serde_json::Value;
|
||||
|
||||
use crate::client::{Client, CreateScriptBody};
|
||||
use crate::config;
|
||||
use crate::output::{OutputMode, Table};
|
||||
use crate::output::{KvBlock, OutputMode, Table};
|
||||
|
||||
pub async fn ls(app: Option<&str>, mode: OutputMode) -> Result<()> {
|
||||
let creds = config::resolve()?;
|
||||
@@ -62,6 +62,7 @@ pub async fn deploy(
|
||||
app_ident: &str,
|
||||
name_override: Option<&str>,
|
||||
description: Option<&str>,
|
||||
mode: OutputMode,
|
||||
) -> Result<()> {
|
||||
let creds = config::resolve()?;
|
||||
let client = Client::from_creds(&creds)?;
|
||||
@@ -87,11 +88,11 @@ pub async fn deploy(
|
||||
let app = client.apps_get(app_ident).await?;
|
||||
|
||||
let existing = client.scripts_list_by_app(app_ident).await?;
|
||||
if let Some(s) = existing.into_iter().find(|s| s.name == name) {
|
||||
let (script, action) = if let Some(s) = existing.into_iter().find(|s| s.name == name) {
|
||||
let updated = client
|
||||
.scripts_update_source(&s.id.to_string(), &source)
|
||||
.await?;
|
||||
println!("Updated {} v{}", updated.name, updated.version);
|
||||
(updated, "updated")
|
||||
} else {
|
||||
let body = CreateScriptBody {
|
||||
app_id: app.app.id,
|
||||
@@ -99,9 +100,18 @@ pub async fn deploy(
|
||||
description,
|
||||
source: &source,
|
||||
};
|
||||
let created = client.scripts_create(&body).await?;
|
||||
println!("Created {} v{}", created.name, created.version);
|
||||
}
|
||||
(client.scripts_create(&body).await?, "created")
|
||||
};
|
||||
// Emit the script object so `--output json` callers can capture the
|
||||
// id for the follow-up routes/triggers calls.
|
||||
let mut block = KvBlock::new();
|
||||
block
|
||||
.field("id", script.id.to_string())
|
||||
.field("name", script.name.clone())
|
||||
.field("version", script.version.to_string())
|
||||
.field("action", action)
|
||||
.field("updated_at", script.updated_at.to_rfc3339());
|
||||
block.print(mode);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user