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
6 changes: 4 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ derive_more = { version = "1", default-features = false, features = ["full"] }
smart-default = "0.7"
tokio = { version = "1", features = ["full"] }
tokio-util = { version = "0.7", features = ["rt"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt", "registry"] }

[workspace.lints.rust]
unsafe_code = "deny"
Expand Down Expand Up @@ -65,8 +67,8 @@ unimplemented = "deny"
mem_forget = "deny"
implicit_clone = "deny"
lossy_float_literal = "deny"
print_stdout = "warn"
print_stderr = "warn"
print_stdout = "deny"
print_stderr = "deny"
unwrap_used = "warn"
expect_used = "warn"
panic = "warn"
Expand Down
2 changes: 1 addition & 1 deletion crates/hm-plugin-cloud/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ reqwest = { version = "0.13", default-features = false, features = ["
tokio = { version = "1", features = ["net", "time", "sync"] }
webbrowser = "1"
dialoguer = "0.11"
tracing = "0.1"
tracing = { workspace = true }

[lints]
workspace = true
6 changes: 3 additions & 3 deletions crates/hm-plugin-cloud/src/auth/login.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ async fn login_loopback(

tracing::info!("opening browser to {auth_url}");
if webbrowser::open(&auth_url).is_err() {
eprintln!("couldn't auto-open the browser. Open this URL manually:\n {auth_url}");
tracing::warn!("couldn't auto-open the browser. Open this URL manually:\n {auth_url}");
}

// Wait for a single connection with a 180-second timeout.
Expand Down Expand Up @@ -98,7 +98,7 @@ async fn login_paste(
"{}/cli/login?challenge={}&redirect_uri=urn:ietf:wg:oauth:2.0:oob",
cfg.api_base, challenge,
);
eprintln!("Open this URL in your browser, then paste the code:\n {auth_url}");
tracing::info!("Open this URL in your browser, then paste the code:\n {auth_url}");
let _ = webbrowser::open(&auth_url);

// Tests inject the code via `HARMONT_LOGIN_CODE` to avoid TTY.
Expand Down Expand Up @@ -132,7 +132,7 @@ async fn finalize(cfg: &Config, code: &str, verifier: &str) -> Result<()> {

let auth_client = Client::new(cfg, Some(resp.token));
let me: User = auth_client.get("/auth/me").await?;
eprintln!(
tracing::info!(
"logged in as {} ({})",
me.display_name.clone().unwrap_or_else(|| me.email.clone()),
me.email,
Expand Down
2 changes: 1 addition & 1 deletion crates/hm-plugin-cloud/src/auth/logout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ use crate::creds;
pub(crate) async fn run(env: &BTreeMap<String, String>) -> Result<()> {
let cfg = Config::from_env(env);
creds::clear_token(&cfg.api_base);
eprintln!("logged out of {}", cfg.api_base);
tracing::info!("logged out of {}", cfg.api_base);
Ok(())
}
2 changes: 1 addition & 1 deletion crates/hm-plugin-cloud/src/auth/whoami.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pub(crate) async fn run(env: &BTreeMap<String, String>) -> Result<()> {
})?;
let client = Client::new(&cfg, Some(token));
let me: User = client.get("/auth/me").await?;
println!(
tracing::info!(
"{} <{}> (id {})",
me.display_name.clone().unwrap_or_else(|| me.email.clone()),
me.email,
Expand Down
14 changes: 11 additions & 3 deletions crates/hm-plugin-cloud/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,11 +158,19 @@ pub async fn dispatch(argv: Vec<String>, env: BTreeMap<String, String>) -> Resul
let msg = e.to_string();
return match e.kind() {
ErrorKind::DisplayHelp | ErrorKind::DisplayVersion => {
print!("{msg}");
#[allow(clippy::print_stdout)]
{
use std::io::Write;
std::io::stdout().write_all(msg.as_bytes()).ok();
}
Ok(0)
}
_ => {
eprint!("{msg}");
#[allow(clippy::print_stderr)]
{
use std::io::Write;
std::io::stderr().write_all(msg.as_bytes()).ok();
}
Ok(2)
}
};
Expand All @@ -187,7 +195,7 @@ pub async fn dispatch_command(command: CloudCommand, env: BTreeMap<String, Strin
match result {
Ok(()) => Ok(0),
Err(e) => {
eprintln!("{e:#}");
tracing::error!("{e:#}");
Ok(1)
}
}
Expand Down
2 changes: 0 additions & 2 deletions crates/hm-plugin-cloud/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
clippy::multiple_crate_versions,
clippy::cargo_common_metadata,
clippy::missing_errors_doc,
clippy::print_stdout,
clippy::print_stderr,
reason = "quick migration from plugin crate; polish later"
)]

Expand Down
14 changes: 7 additions & 7 deletions crates/hm-plugin-cloud/src/verbs/billing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ async fn balance(client: &Client, org: &str) -> Result<()> {
.get(&format!("/organizations/{org}/billing/balance"))
.await?;
let dollars = b.credits_usd_cents as f64 / 100.0;
println!("${dollars:.2}");
tracing::info!("${dollars:.2}");
Ok(())
}

Expand All @@ -51,7 +51,7 @@ async fn transactions(client: &Client, org: &str, limit: u32) -> Result<()> {
))
.await?;
for t in &list.data {
println!(
tracing::info!(
"{} {:>10} {:<14} {}",
t.at.format("%Y-%m-%d %H:%M:%S"),
t.amount_cents,
Expand All @@ -78,7 +78,7 @@ async fn usage(client: &Client, org: &str, from: Option<&str>, to: Option<&str>)
let u: UsageWindow = client
.get(&format!("/organizations/{org}/billing/usage{qs}"))
.await?;
println!(
tracing::info!(
"{} -> {}: {:.2} min, ${:.2}",
u.from.format("%Y-%m-%d"),
u.to.format("%Y-%m-%d"),
Expand All @@ -99,10 +99,10 @@ async fn topup(client: &Client, org: &str, amount_usd: u32, no_browser: bool) ->
)
.await?;
if no_browser {
println!("{}", r.checkout_url);
tracing::info!("{}", r.checkout_url);
} else if webbrowser::open(&r.checkout_url).is_err() {
eprintln!("couldn't open browser; URL:");
eprintln!("{}", r.checkout_url);
tracing::warn!("couldn't open browser; URL:");
tracing::warn!("{}", r.checkout_url);
}
Ok(())
}
Expand All @@ -118,7 +118,7 @@ async fn redeem(client: &Client, org: &str, code: &str) -> Result<()> {
)
.await?;
let dollars = r.credited_cents as f64 / 100.0;
eprintln!("credited ${dollars:.2}");
tracing::info!("credited ${dollars:.2}");
Ok(())
}

Expand Down
8 changes: 4 additions & 4 deletions crates/hm-plugin-cloud/src/verbs/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ async fn list(client: &Client, org: &str, pipe: &str) -> Result<()> {
.get(&format!("/organizations/{org}/pipelines/{pipe}/builds"))
.await?;
for b in &builds.data {
println!(
tracing::info!(
"#{:<5} {:<10} {}",
b.number,
b.state,
Expand All @@ -48,7 +48,7 @@ async fn show(client: &Client, org: &str, pipe: &str, number: i64) -> Result<()>
))
.await?;
let json = serde_json::to_string_pretty(&b).unwrap_or_default();
println!("{json}");
tracing::info!("{json}");
Ok(())
}

Expand All @@ -59,7 +59,7 @@ async fn cancel(client: &Client, org: &str, pipe: &str, number: i64) -> Result<(
&serde_json::json!({}),
)
.await?;
eprintln!("build #{number} cancelled");
tracing::info!("build #{number} cancelled");
Ok(())
}

Expand All @@ -72,7 +72,7 @@ async fn watch(client: &Client, org: &str, pipe: &str, number: i64) -> Result<()
))
.await?;
if b.state != last_state {
eprintln!("state: {last_state} -> {}", b.state);
tracing::info!("state: {last_state} -> {}", b.state);
last_state = b.state.clone();
}
match b.state.as_str() {
Expand Down
6 changes: 3 additions & 3 deletions crates/hm-plugin-cloud/src/verbs/job.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ async fn list(client: &Client, org: &str, pipe: &str, build: i64) -> Result<()>
))
.await?;
for j in &jobs.data {
println!(
tracing::info!(
"{} {:<10} {}",
j.id,
j.state,
Expand All @@ -56,7 +56,7 @@ async fn show(client: &Client, org: &str, pipe: &str, build: i64, jid: &str) ->
"/organizations/{org}/pipelines/{pipe}/builds/{build}/jobs/{jid}"
))
.await?;
println!("{}", serde_json::to_string_pretty(&j).unwrap_or_default());
tracing::info!("{}", serde_json::to_string_pretty(&j).unwrap_or_default());
Ok(())
}

Expand All @@ -67,7 +67,7 @@ async fn log_cmd(client: &Client, org: &str, pipe: &str, build: i64, jid: &str)
))
.await?;
for chunk in &log.data {
println!("{}", chunk.line);
tracing::info!("{}", chunk.line);
}
Ok(())
}
Expand Down
2 changes: 1 addition & 1 deletion crates/hm-plugin-cloud/src/verbs/org.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,6 @@ async fn switch(client: &Client, slug: &str) -> Result<()> {
let mut state = CloudState::load();
state.active_org = Some(found.slug.clone());
state.save();
eprintln!("active organization: {} ({})", found.name, found.slug);
tracing::info!("active organization: {} ({})", found.name, found.slug);
Ok(())
}
4 changes: 2 additions & 2 deletions crates/hm-plugin-cloud/src/verbs/pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ async fn list(client: &Client, org: &str) -> Result<()> {
.get(&format!("/organizations/{org}/pipelines"))
.await?;
for p in &pipes.data {
println!(
tracing::info!(
"{:<24} {}",
p.slug,
p.label.as_deref().unwrap_or("(no label)")
Expand All @@ -49,7 +49,7 @@ async fn show(client: &Client, org: &str, slug: &str) -> Result<()> {
"default_branch": p.default_branch,
}))
.unwrap_or_default();
println!("{json}");
tracing::info!("{json}");
Ok(())
}

Expand Down
2 changes: 1 addition & 1 deletion crates/hm-plugin-cloud/src/verbs/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ pub(crate) async fn run(env: &BTreeMap<String, String>, args: RunArgs) -> Result
args.pipeline,
build.number
);
eprintln!("submitted build #{}: {url}", build.number);
tracing::info!("submitted build #{}: {url}", build.number);
if args.no_watch {
return Ok(());
}
Expand Down
4 changes: 2 additions & 2 deletions crates/hm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ tempfile = "3"
anyhow = "1"
thiserror = "2"
backon = "1"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"] }
tracing = { workspace = true }
tracing-subscriber = { workspace = true }
chrono = { version = "0.4", features = ["serde"] }
url = "2"
base64 = "0.22"
Expand Down
4 changes: 2 additions & 2 deletions crates/hm/src/cli/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub async fn run(cmd: PluginCommand) -> Result<()> {

#[allow(clippy::unused_async)]
async fn list() -> Result<()> {
println!("Registered runners:");
println!(" docker (default, built-in)");
tracing::info!("Registered runners:");
tracing::info!(" docker (default, built-in)");
Ok(())
}
2 changes: 1 addition & 1 deletion crates/hm/src/cli/version.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ use anyhow::Result;
///
/// Returns an error on I/O failure.
pub async fn run() -> Result<()> {
println!("hm {}", env!("CARGO_PKG_VERSION"));
tracing::info!("hm {}", env!("CARGO_PKG_VERSION"));
Ok(())
}
8 changes: 2 additions & 6 deletions crates/hm/src/commands/dev/down.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@ use super::naming::{
/// # Errors
///
/// Returns Docker errors on list / stop / remove failures.
#[allow(
clippy::print_stderr,
reason = "status messages to stderr are intentional for a foreground CLI"
)]
pub async fn handle(args: DevDownArgs, _ctx: RunContext) -> Result<i32> {
let docker = DockerClient::connect()?;
let worktree_root = resolve_worktree_root()?;
Expand Down Expand Up @@ -60,15 +56,15 @@ pub async fn handle(args: DevDownArgs, _ctx: RunContext) -> Result<i32> {
}

if to_remove.is_empty() {
eprintln!("[hm] nothing to sweep");
tracing::info!("[hm] nothing to sweep");
return Ok(0);
}

let mut sessions_swept = BTreeSet::<String>::default();
for (id, slug, session, name) in &to_remove {
let _ = docker.stop_container(id).await;
let _ = docker.remove_container(id).await;
eprintln!("[hm] removed {name} (slug={slug}, session={session})");
tracing::info!("[hm] removed {name} (slug={slug}, session={session})");
sessions_swept.insert(session.clone());
}

Expand Down
11 changes: 4 additions & 7 deletions crates/hm/src/commands/dev/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@ use super::naming::{
///
/// Returns an error if Docker is unreachable or if the exec lifecycle
/// calls fail.
#[allow(
clippy::print_stderr,
reason = "user-facing error messages for a foreground CLI"
)]
pub async fn handle(args: DevExecArgs, _ctx: RunContext) -> Result<i32> {
let docker = DockerClient::connect()?;
let worktree_root = resolve_worktree_root()?;
Expand All @@ -44,14 +40,15 @@ pub async fn handle(args: DevExecArgs, _ctx: RunContext) -> Result<i32> {
}
}
if matches.is_empty() {
eprintln!(
tracing::error!(
"hm: slug `{}` is not running in this worktree.\n → run `hm dev up {}` first.",
args.slug, args.slug,
args.slug,
args.slug,
);
return Ok(4);
}
if matches.len() > 1 {
eprintln!(
tracing::error!(
"hm: slug `{}` matches multiple live sessions; pass --session <id>",
args.slug
);
Expand Down
11 changes: 4 additions & 7 deletions crates/hm/src/commands/dev/logs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,6 @@ use super::naming::{
/// # Errors
///
/// Returns an error if Docker is unreachable.
#[allow(
clippy::print_stderr,
reason = "user-facing error messages for a foreground CLI"
)]
pub async fn handle(args: DevLogsArgs, _ctx: RunContext) -> Result<i32> {
let docker = DockerClient::connect()?;
let worktree_root = resolve_worktree_root()?;
Expand All @@ -47,14 +43,15 @@ pub async fn handle(args: DevLogsArgs, _ctx: RunContext) -> Result<i32> {
}
}
if matches.is_empty() {
eprintln!(
tracing::error!(
"hm: slug `{}` is not running in this worktree.\n → run `hm dev up {}` first.",
args.slug, args.slug,
args.slug,
args.slug,
);
return Ok(4);
}
if matches.len() > 1 {
eprintln!(
tracing::error!(
"hm: slug `{}` matches multiple live sessions; pass --session <id>",
args.slug
);
Expand Down
Loading
Loading