Skip to main content

ralph/cli/
version.rs

1//! Version command for Ralph CLI.
2//!
3//! Responsibilities:
4//! - Display version information including package version, git commit, and build timestamp.
5//! - Provide both simple and verbose output modes for version details.
6//!
7//! Not handled here:
8//! - Version bumping or release management (see release workflow).
9//! - Changelog generation or modification.
10//!
11//! Invariants/assumptions:
12//! - Version info is captured at compile time via environment variables set by the build script.
13//! - Git info may be unavailable (e.g., building from tarball), in which case it is omitted gracefully.
14
15use anyhow::Result;
16
17/// Arguments for the version command.
18#[derive(clap::Args, Debug)]
19pub struct VersionArgs {
20    /// Show extended build information including git commit and build date
21    #[arg(short, long)]
22    pub verbose: bool,
23}
24
25/// Display version information for Ralph CLI.
26///
27/// Prints the package version by default. With --verbose, also displays
28/// git commit hash and build timestamp when available.
29pub fn handle_version(args: VersionArgs) -> Result<()> {
30    let pkg_name = env!("CARGO_PKG_NAME");
31    let pkg_version = env!("CARGO_PKG_VERSION");
32
33    if args.verbose {
34        println!("{} {}", pkg_name, pkg_version);
35        println!();
36        println!("Build Info:");
37
38        if let Some(git_sha) = option_env!("VERGEN_GIT_SHA") {
39            println!("  Git commit: {}", git_sha);
40        }
41
42        if let Some(build_timestamp) = option_env!("VERGEN_BUILD_TIMESTAMP") {
43            println!("  Build date: {}", build_timestamp);
44        }
45    } else {
46        println!("{} {}", pkg_name, pkg_version);
47    }
48
49    Ok(())
50}
51
52#[cfg(test)]
53mod tests {
54    use super::*;
55    use crate::cli::{Cli, Command};
56    use clap::Parser;
57
58    #[test]
59    fn cli_parses_version_command() {
60        let cli = Cli::try_parse_from(["ralph", "version"]).expect("parse");
61        match cli.command {
62            Command::Version(args) => {
63                assert!(!args.verbose);
64            }
65            _ => panic!("expected version command"),
66        }
67    }
68
69    #[test]
70    fn cli_parses_version_verbose() {
71        let cli = Cli::try_parse_from(["ralph", "version", "--verbose"]).expect("parse");
72        match cli.command {
73            Command::Version(args) => {
74                assert!(args.verbose);
75            }
76            _ => panic!("expected version command"),
77        }
78    }
79
80    #[test]
81    fn cli_parses_version_verbose_short() {
82        let cli = Cli::try_parse_from(["ralph", "version", "-v"]).expect("parse");
83        match cli.command {
84            Command::Version(args) => {
85                assert!(args.verbose);
86            }
87            _ => panic!("expected version command"),
88        }
89    }
90
91    #[test]
92    fn handle_version_default_output() {
93        let args = VersionArgs { verbose: false };
94        // Should not panic or error
95        let result = handle_version(args);
96        assert!(result.is_ok());
97    }
98
99    #[test]
100    fn handle_version_verbose_output() {
101        let args = VersionArgs { verbose: true };
102        // Should not panic or error
103        let result = handle_version(args);
104        assert!(result.is_ok());
105    }
106}