From 3ea67da807cc1b6c09aafc3d4ef4d7f78c502a9c Mon Sep 17 00:00:00 2001 From: majiayu000 <1835304752@qq.com> Date: Fri, 26 Dec 2025 11:59:18 +0800 Subject: [PATCH] fix: improve error message for partial version numbers When users specify partial versions like "18" instead of "18.0.0", Volta now provides a more helpful error message that: - Explains that Volta requires full semantic versions (major.minor.patch) - Indicates that partial versions are not supported - Suggests the complete version format (e.g., "18.0.0") For other invalid version strings, the error now clearly states the required format. Fixes #1433 Signed-off-by: majiayu000 <1835304752@qq.com> --- crates/volta-core/src/error/kind.rs | 78 ++++++++++++++++++++++++++--- 1 file changed, 72 insertions(+), 6 deletions(-) diff --git a/crates/volta-core/src/error/kind.rs b/crates/volta-core/src/error/kind.rs index 6add88efa..0140d21ac 100644 --- a/crates/volta-core/src/error/kind.rs +++ b/crates/volta-core/src/error/kind.rs @@ -1356,13 +1356,37 @@ To upgrade it, please use the command `{} {0}`"#, package, name, command ) } - ErrorKind::VersionParseError { version } => write!( - f, - r#"Could not parse version "{}" + ErrorKind::VersionParseError { version } => { + // Check if the version looks like a partial version (just major or major.minor) + let parts: Vec<&str> = version.split('.').collect(); + let is_partial = parts.len() < 3 && parts.iter().all(|p| p.chars().all(|c| c.is_ascii_digit())); + + if is_partial { + // Build the suggested full version by appending missing parts + let suggested = match parts.len() { + 1 => format!("{}.0.0", version), + 2 => format!("{}.0", version), + _ => version.clone(), + }; + write!( + f, + r#"Could not parse version "{version}" + +Volta requires a full semantic version (major.minor.patch format). +Partial versions like "{version}" are not supported. + +Please specify the complete version, for example: "{suggested}""# + ) + } else { + write!( + f, + r#"Could not parse version "{version}" -Please verify the intended version."#, - version - ), +Volta requires a valid semantic version in major.minor.patch format (e.g., "18.0.0"). +Please verify the version string is correctly formatted."# + ) + } + } ErrorKind::WriteBinConfigError { file } => write!( f, "Could not write executable configuration @@ -1580,3 +1604,45 @@ impl ErrorKind { } } } + +#[cfg(test)] +mod tests { + use super::ErrorKind; + + #[test] + fn version_parse_error_partial_major_version() { + let error = ErrorKind::VersionParseError { + version: "18".into(), + }; + let message = format!("{}", error); + assert!(message.contains("Could not parse version \"18\"")); + assert!(message.contains("Volta requires a full semantic version")); + assert!(message.contains("Partial versions like \"18\" are not supported")); + assert!(message.contains("\"18.0.0\"")); + } + + #[test] + fn version_parse_error_partial_minor_version() { + let error = ErrorKind::VersionParseError { + version: "18.0".into(), + }; + let message = format!("{}", error); + assert!(message.contains("Could not parse version \"18.0\"")); + assert!(message.contains("Volta requires a full semantic version")); + assert!(message.contains("Partial versions like \"18.0\" are not supported")); + assert!(message.contains("\"18.0.0\"")); + } + + #[test] + fn version_parse_error_invalid_version() { + let error = ErrorKind::VersionParseError { + version: "invalid-version".into(), + }; + let message = format!("{}", error); + assert!(message.contains("Could not parse version \"invalid-version\"")); + assert!( + message.contains("Volta requires a valid semantic version in major.minor.patch format") + ); + assert!(!message.contains("Partial versions")); + } +}