feat: add username/password flags to create-token command

This commit is contained in:
Jon Seager 2025-11-26 16:32:40 +00:00
parent 65e1e141ea
commit 02824a90f1
No known key found for this signature in database
4 changed files with 53 additions and 38 deletions

View file

@ -48,6 +48,10 @@ First, create an API token:
```bash
brewlog create-token --name "my-cli-token"
# You will be prompted for username and password.
# Alternatively, you can provide them via flags:
# brewlog create-token --name "my-cli-token" --username admin --password secret
# Username: admin
# Password: ********
#

View file

@ -11,6 +11,14 @@ pub struct CreateTokenCommand {
/// A descriptive name for this token
#[arg(long)]
pub name: String,
/// The username to authenticate with
#[arg(long)]
pub username: Option<String>,
/// The password to authenticate with
#[arg(long)]
pub password: Option<String>,
}
#[derive(Debug, Args)]
@ -21,20 +29,28 @@ pub struct RevokeTokenCommand {
}
pub async fn create_token(client: &BrewlogClient, cmd: CreateTokenCommand) -> Result<()> {
// Prompt for username
print!("Username: ");
io::stdout().flush()?;
let mut username = String::new();
io::stdin().read_line(&mut username)?;
let username = username.trim();
let username = if let Some(u) = cmd.username {
u
} else {
// Prompt for username
print!("Username: ");
io::stdout().flush()?;
let mut username = String::new();
io::stdin().read_line(&mut username)?;
username.trim().to_string()
};
// Prompt for password (without echo)
let password = rpassword::prompt_password("Password: ").context("failed to read password")?;
let password = if let Some(p) = cmd.password {
p
} else {
// Prompt for password (without echo)
rpassword::prompt_password("Password: ").context("failed to read password")?
};
// Create the token
let token_response = client
.tokens()
.create(username, &password, &cmd.name)
.create(&username, &password, &cmd.name)
.await?;
println!("\nToken created successfully!");

View file

@ -113,40 +113,38 @@ pub fn server_info() -> (String, String) {
ensure_server_started().expect("Failed to start test server")
}
/// Create a token for testing using the API directly
/// Create a token for testing using the CLI
pub fn create_token(name: &str) -> String {
let (address, password) = ensure_server_started().expect("Failed to start test server");
let (_, password) = ensure_server_started().expect("Failed to start test server");
let client = reqwest::blocking::Client::builder()
.timeout(Duration::from_secs(5))
.build()
.expect("Failed to create HTTP client");
let output = run_brewlog(
&[
"create-token",
"--name",
name,
"--username",
"admin",
"--password",
&password,
],
&[],
);
let response = client
.post(format!("{}/api/v1/tokens", address))
.json(&serde_json::json!({
"username": "admin",
"password": password,
"name": name
}))
.send()
.expect("Failed to send token creation request");
if !response.status().is_success() {
if !output.status.success() {
panic!(
"Failed to create token: status={} body={}",
response.status(),
response.text().unwrap_or_default()
"Failed to create token: {}",
String::from_utf8_lossy(&output.stderr)
);
}
let token_response: serde_json::Value =
response.json().expect("Failed to parse token response");
let stdout = String::from_utf8_lossy(&output.stdout);
for line in stdout.lines() {
if let Some(token) = line.trim().strip_prefix("export BREWLOG_TOKEN=") {
return token.to_string();
}
}
token_response["token"]
.as_str()
.expect("Token not found in response")
.to_string()
panic!("Could not find token in output: {}", stdout);
}
/// Run a brewlog CLI command and return the output

View file

@ -1,8 +1,5 @@
use crate::helpers::{create_token, run_brewlog, server_info};
// Note: create-token CLI command tests are omitted due to stdin handling complexity.
// Token creation for testing is done via API in the create_token() helper.
#[test]
fn test_list_tokens_requires_authentication() {
let _ = server_info();