Skip to content

Commit 311948f

Browse files
Merge branch 'main' into max/dataset-versions
2 parents 74d9e4e + 92730b8 commit 311948f

26 files changed

Lines changed: 6850 additions & 619 deletions

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "bt"
3-
version = "0.4.0"
3+
version = "0.5.0"
44
edition = "2021"
55
rust-version = "1.86.0"
66
authors = ["Braintrust engineering <eng@braintrust.dev>"]

README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -266,10 +266,11 @@ Local transaction-id conversion helpers:
266266

267267
Auth resolution order for commands is:
268268

269-
1. `--api-key` or `BRAINTRUST_API_KEY` (unless `--prefer-profile` is set)
270-
2. `--profile` or `BRAINTRUST_PROFILE`
271-
3. Org-based profile match (profile whose org matches `--org`/config org)
272-
4. Single-profile auto-select (if only one profile exists)
269+
1. Explicit `--profile`
270+
2. `--api-key` or `BRAINTRUST_API_KEY` (unless `--prefer-profile` is set)
271+
3. `BRAINTRUST_PROFILE`
272+
4. Org-based profile match (profile whose org matches `--org`/config org)
273+
5. Single-profile auto-select (if only one profile exists)
273274

274275
On Linux, secure storage uses `secret-tool` (libsecret) with a running Secret Service daemon. On macOS, it uses the `security` keychain utility. If a secure store is unavailable, `bt` falls back to a plaintext secrets file with `0600` permissions.
275276

src/args.rs

Lines changed: 89 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,45 @@
1+
use std::ffi::OsString;
12
use std::path::PathBuf;
23

34
use clap::Args;
45

56
pub use braintrust_sdk_rust::{DEFAULT_API_URL, DEFAULT_APP_URL};
67

8+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9+
pub enum ArgValueSource {
10+
CommandLine,
11+
EnvVariable,
12+
}
13+
714
#[derive(Debug, Clone, Args)]
815
pub struct BaseArgs {
916
/// Output as JSON
1017
#[arg(long, global = true)]
1118
pub json: bool,
1219

13-
/// Suppress non-essential output
20+
/// Verbose mode — set at runtime by subcommands that support it
21+
#[arg(skip)]
22+
pub verbose: bool,
23+
24+
/// Reduce interactive UI output
1425
#[arg(long, short = 'q', env = "BRAINTRUST_QUIET", global = true, value_parser = clap::builder::BoolishValueParser::new(), default_value_t = false)]
1526
pub quiet: bool,
1627

1728
/// Disable ANSI color output
1829
#[arg(long, env = "BRAINTRUST_NO_COLOR", global = true, value_parser = clap::builder::BoolishValueParser::new(), default_value_t = false)]
1930
pub no_color: bool,
2031

32+
/// Disable all interactive prompts
33+
#[arg(long, env = "BRAINTRUST_NO_INPUT", global = true, value_parser = clap::builder::BoolishValueParser::new(), default_value_t = false)]
34+
pub no_input: bool,
35+
2136
/// Use a saved login profile (or via BRAINTRUST_PROFILE)
2237
#[arg(long, env = "BRAINTRUST_PROFILE", global = true)]
2338
pub profile: Option<String>,
2439

40+
#[arg(skip = false)]
41+
pub profile_explicit: bool,
42+
2543
/// Override active org (or via BRAINTRUST_ORG_NAME)
2644
#[arg(short = 'o', long = "org", env = "BRAINTRUST_ORG_NAME", global = true)]
2745
pub org_name: Option<String>,
@@ -40,14 +58,13 @@ pub struct BaseArgs {
4058
#[arg(long, env = "BRAINTRUST_API_KEY", global = true, hide = true)]
4159
pub api_key: Option<String>,
4260

61+
#[arg(skip)]
62+
pub api_key_source: Option<ArgValueSource>,
63+
4364
/// Prefer profile credentials even if BRAINTRUST_API_KEY/--api-key is set.
4465
#[arg(long, global = true)]
4566
pub prefer_profile: bool,
4667

47-
/// Disable all interactive prompts
48-
#[arg(long, global = true)]
49-
pub no_input: bool,
50-
5168
/// Override API URL (or via BRAINTRUST_API_URL)
5269
#[arg(
5370
long,
@@ -67,7 +84,12 @@ pub struct BaseArgs {
6784
pub app_url: Option<String>,
6885

6986
/// Path to a .env file to load before running commands.
70-
#[arg(long, env = "BRAINTRUST_ENV_FILE", hide_env_values = true)]
87+
#[arg(
88+
long,
89+
env = "BRAINTRUST_ENV_FILE",
90+
hide_env_values = true,
91+
global = true
92+
)]
7193
pub env_file: Option<PathBuf>,
7294
}
7395

@@ -79,3 +101,64 @@ pub struct CLIArgs<T: Args> {
79101
#[command(flatten)]
80102
pub args: T,
81103
}
104+
105+
pub fn has_explicit_profile_arg(args: &[OsString]) -> bool {
106+
let mut idx = 1usize;
107+
while idx < args.len() {
108+
let Some(arg) = args[idx].to_str() else {
109+
idx += 1;
110+
continue;
111+
};
112+
113+
if arg == "--" {
114+
break;
115+
}
116+
117+
if arg == "--profile" || arg.starts_with("--profile=") {
118+
return true;
119+
}
120+
121+
idx += 1;
122+
}
123+
124+
false
125+
}
126+
127+
#[cfg(test)]
128+
mod tests {
129+
use super::has_explicit_profile_arg;
130+
use std::ffi::OsString;
131+
132+
#[test]
133+
fn has_explicit_profile_arg_detects_split_flag() {
134+
let args = vec![
135+
OsString::from("bt"),
136+
OsString::from("status"),
137+
OsString::from("--profile"),
138+
OsString::from("work"),
139+
];
140+
assert!(has_explicit_profile_arg(&args));
141+
}
142+
143+
#[test]
144+
fn has_explicit_profile_arg_detects_equals_flag() {
145+
let args = vec![
146+
OsString::from("bt"),
147+
OsString::from("status"),
148+
OsString::from("--profile=work"),
149+
];
150+
assert!(has_explicit_profile_arg(&args));
151+
}
152+
153+
#[test]
154+
fn has_explicit_profile_arg_ignores_passthrough_args() {
155+
let args = vec![
156+
OsString::from("bt"),
157+
OsString::from("eval"),
158+
OsString::from("--"),
159+
OsString::from("--profile"),
160+
OsString::from("work"),
161+
];
162+
assert!(!has_explicit_profile_arg(&args));
163+
}
164+
}

0 commit comments

Comments
 (0)