use crate::error::OpencodeError;
use crate::error::Result;
pub const PINNED_OPENCODE_VERSION: &str = "1.3.17";
pub const OPENCODE_BINARY_ENV: &str = "OPENCODE_BINARY";
pub const OPENCODE_BINARY_ARGS_ENV: &str = "OPENCODE_BINARY_ARGS";
pub fn normalize_version(raw: &str) -> &str {
let trimmed = raw.trim();
trimmed.strip_prefix('v').unwrap_or(trimmed)
}
pub fn validate_exact_version(actual: Option<&str>) -> Result<()> {
let Some(actual) = actual else {
return Err(OpencodeError::VersionMismatch {
expected: PINNED_OPENCODE_VERSION.to_string(),
actual: "None".to_string(),
});
};
let normalized = normalize_version(actual);
if normalized != PINNED_OPENCODE_VERSION {
return Err(OpencodeError::VersionMismatch {
expected: PINNED_OPENCODE_VERSION.to_string(),
actual: actual.to_string(),
});
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_normalize_version_strips_v_prefix() {
assert_eq!(normalize_version("v1.3.17"), "1.3.17");
assert_eq!(normalize_version("1.3.17"), "1.3.17");
assert_eq!(normalize_version(" v1.3.17 "), "1.3.17");
}
#[test]
fn test_validate_exact_version_accepts_matching() {
assert!(validate_exact_version(Some(PINNED_OPENCODE_VERSION)).is_ok());
assert!(validate_exact_version(Some(&format!("v{PINNED_OPENCODE_VERSION}"))).is_ok());
}
#[test]
fn test_validate_exact_version_rejects_mismatch() {
assert!(validate_exact_version(Some("1.3.12")).is_err());
assert!(validate_exact_version(Some("1.4.0")).is_err());
assert!(validate_exact_version(None).is_err());
}
}