feat(cli): warn on client/server version mismatch in fabro version

When stderr is a TTY and text output is used, print a yellow `warning:`
line on stderr if the server reports a version that differs from the
client. JSON output and non-interactive contexts stay silent.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Bryan Helmkamp 2026-04-18 09:33:44 -04:00
parent 0d9f71d1cb
commit 65baf1240b
No known key found for this signature in database

View file

@ -1,3 +1,5 @@
use std::io::IsTerminal;
use anyhow::Result;
use fabro_types::settings::CliSettings;
use fabro_types::settings::cli::{CliLayer, OutputFormat};
@ -57,9 +59,41 @@ pub(crate) async fn version_command(
}
print_text_output(&client, &server_info);
warn_on_version_mismatch(&client, &server_info, printer);
Ok(())
}
fn warn_on_version_mismatch(
client: &ClientVersionInfo,
server: &ServerVersionInfo,
printer: Printer,
) {
if !std::io::stderr().is_terminal() {
return;
}
let Some(message) = version_mismatch_message(client.version, server) else {
return;
};
let yellow = console::Style::new().yellow();
fabro_util::printerr!(printer, "\n{} {}", yellow.apply_to("warning:"), message);
}
fn version_mismatch_message(client_version: &str, server: &ServerVersionInfo) -> Option<String> {
let ServerVersionInfo::Success {
version: Some(server_version),
..
} = server
else {
return None;
};
if server_version == client_version {
return None;
}
Some(format!(
"client version ({client_version}) does not match server version ({server_version})"
))
}
struct ClientVersionInfo {
version: &'static str,
git_sha: &'static str,
@ -210,3 +244,53 @@ fn format_uptime(total_secs: i64) -> String {
format!("{seconds}s")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn version_mismatch_message_covers_all_branches() {
let matching = ServerVersionInfo::Success {
address: "http://localhost".into(),
version: Some("1.0.0".into()),
git_sha: None,
build_date: None,
os: None,
arch: None,
uptime_secs: None,
};
assert_eq!(version_mismatch_message("1.0.0", &matching), None);
let mismatched = ServerVersionInfo::Success {
address: "http://localhost".into(),
version: Some("1.2.0".into()),
git_sha: None,
build_date: None,
os: None,
arch: None,
uptime_secs: None,
};
assert_eq!(
version_mismatch_message("1.0.0", &mismatched).as_deref(),
Some("client version (1.0.0) does not match server version (1.2.0)")
);
let unknown = ServerVersionInfo::Success {
address: "http://localhost".into(),
version: None,
git_sha: None,
build_date: None,
os: None,
arch: None,
uptime_secs: None,
};
assert_eq!(version_mismatch_message("1.0.0", &unknown), None);
let errored = ServerVersionInfo::Error {
address: "http://localhost".into(),
error: "oops".into(),
};
assert_eq!(version_mismatch_message("1.0.0", &errored), None);
}
}