mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-07 05:43:14 +00:00
feat: enhance version function with automatic version increment (#227)
This commit is contained in:
+4
-4
@@ -199,7 +199,7 @@ async fn run(opt: config::Opt) -> Result<()> {
|
||||
if result.update_available {
|
||||
if let Some(latest) = &result.latest_version {
|
||||
info!(
|
||||
"🚀 New version available: {} -> {} (current: {})",
|
||||
"🚀 Version check: New version available: {} -> {} (current: {})",
|
||||
result.current_version, latest.version, result.current_version
|
||||
);
|
||||
if let Some(notes) = &latest.release_notes {
|
||||
@@ -210,14 +210,14 @@ async fn run(opt: config::Opt) -> Result<()> {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
debug!("✅ Current version is up to date: {}", result.current_version);
|
||||
debug!("✅ Version check: Current version is up to date: {}", result.current_version);
|
||||
}
|
||||
}
|
||||
Err(UpdateCheckError::HttpError(e)) => {
|
||||
debug!("Version check network error (this is normal): {}", e);
|
||||
debug!("Version check: network error (this is normal): {}", e);
|
||||
}
|
||||
Err(e) => {
|
||||
debug!("Version check failed (this is normal): {}", e);
|
||||
debug!("Version check: failed (this is normal): {}", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
+22
-103
@@ -15,7 +15,7 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
use thiserror::Error;
|
||||
use tracing::{debug, error, info, warn};
|
||||
use tracing::{debug, error, info};
|
||||
|
||||
use crate::version;
|
||||
|
||||
@@ -86,7 +86,7 @@ impl VersionChecker {
|
||||
|
||||
Self {
|
||||
client,
|
||||
version_url: "https://version.rustfs.com".to_string(),
|
||||
version_url: "https://version.rustfs.com/latest.json".to_string(),
|
||||
timeout: Duration::from_secs(10),
|
||||
}
|
||||
}
|
||||
@@ -139,8 +139,9 @@ impl VersionChecker {
|
||||
|
||||
debug!("Retrieved latest version information: {:?}", version_info);
|
||||
|
||||
// Compare versions
|
||||
let update_available = self.is_newer_version(¤t_version, &version_info.version)?;
|
||||
// Compare versions using version.rs functions
|
||||
let update_available = version::is_newer_version(¤t_version, &version_info.version)
|
||||
.map_err(|e| UpdateCheckError::VersionParseError(e.to_string()))?;
|
||||
|
||||
let result = UpdateCheckResult {
|
||||
update_available,
|
||||
@@ -161,74 +162,6 @@ impl VersionChecker {
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// Compare version numbers to determine if there's an update
|
||||
fn is_newer_version(&self, current: &str, latest: &str) -> Result<bool, UpdateCheckError> {
|
||||
// Clean version numbers, remove prefixes like "v", "RELEASE.", etc.
|
||||
let current_clean = self.clean_version(current);
|
||||
let latest_clean = self.clean_version(latest);
|
||||
|
||||
debug!("Version comparison: current='{}' vs latest='{}'", current_clean, latest_clean);
|
||||
|
||||
// If versions are the same, no update is needed
|
||||
if current_clean == latest_clean {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
// Try semantic version comparison
|
||||
match self.compare_semantic_versions(¤t_clean, &latest_clean) {
|
||||
Ok(is_newer) => Ok(is_newer),
|
||||
Err(_) => {
|
||||
// If semantic version comparison fails, use string comparison
|
||||
warn!("Semantic version comparison failed, using string comparison");
|
||||
Ok(latest_clean > current_clean)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Clean version string
|
||||
fn clean_version(&self, version: &str) -> String {
|
||||
version
|
||||
.trim()
|
||||
.trim_start_matches('v')
|
||||
.trim_start_matches("RELEASE.")
|
||||
.trim_start_matches('@')
|
||||
.to_string()
|
||||
}
|
||||
|
||||
/// Semantic version comparison
|
||||
fn compare_semantic_versions(&self, current: &str, latest: &str) -> Result<bool, UpdateCheckError> {
|
||||
let current_parts = self.parse_version_parts(current)?;
|
||||
let latest_parts = self.parse_version_parts(latest)?;
|
||||
|
||||
// Use tuple comparison for lexicographic ordering
|
||||
Ok(latest_parts > current_parts)
|
||||
}
|
||||
|
||||
/// Parse version parts (major, minor, patch)
|
||||
fn parse_version_parts(&self, version: &str) -> Result<(u32, u32, u32), UpdateCheckError> {
|
||||
let parts: Vec<&str> = version.split('.').collect();
|
||||
|
||||
if parts.len() < 3 {
|
||||
return Err(UpdateCheckError::VersionParseError(format!("Invalid version format: {version}")));
|
||||
}
|
||||
|
||||
let major = parts[0]
|
||||
.parse::<u32>()
|
||||
.map_err(|_| UpdateCheckError::VersionParseError(format!("Cannot parse major version: {}", parts[0])))?;
|
||||
|
||||
let minor = parts[1]
|
||||
.parse::<u32>()
|
||||
.map_err(|_| UpdateCheckError::VersionParseError(format!("Cannot parse minor version: {}", parts[1])))?;
|
||||
|
||||
// Patch version may contain other characters, only take numeric part
|
||||
let patch_str = parts[2].chars().take_while(|c| c.is_numeric()).collect::<String>();
|
||||
let patch = patch_str
|
||||
.parse::<u32>()
|
||||
.map_err(|_| UpdateCheckError::VersionParseError(format!("Cannot parse patch version: {}", parts[2])))?;
|
||||
|
||||
Ok((major, minor, patch))
|
||||
}
|
||||
}
|
||||
|
||||
/// Get current version number
|
||||
@@ -253,37 +186,6 @@ pub async fn check_updates_with_url(url: String) -> Result<UpdateCheckResult, Up
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_clean_version() {
|
||||
let checker = VersionChecker::new();
|
||||
|
||||
assert_eq!(checker.clean_version("v1.0.0"), "1.0.0");
|
||||
assert_eq!(checker.clean_version("RELEASE.1.0.0"), "1.0.0");
|
||||
assert_eq!(checker.clean_version("@1.0.0"), "1.0.0");
|
||||
assert_eq!(checker.clean_version("1.0.0"), "1.0.0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_version_parts() {
|
||||
let checker = VersionChecker::new();
|
||||
|
||||
assert_eq!(checker.parse_version_parts("1.0.0").unwrap(), (1, 0, 0));
|
||||
assert_eq!(checker.parse_version_parts("2.1.3").unwrap(), (2, 1, 3));
|
||||
assert_eq!(checker.parse_version_parts("1.0.0-beta").unwrap(), (1, 0, 0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_version_comparison() {
|
||||
let checker = VersionChecker::new();
|
||||
|
||||
// Test semantic version comparison
|
||||
assert!(checker.is_newer_version("1.0.0", "1.0.1").unwrap());
|
||||
assert!(checker.is_newer_version("1.0.0", "1.1.0").unwrap());
|
||||
assert!(checker.is_newer_version("1.0.0", "2.0.0").unwrap());
|
||||
assert!(!checker.is_newer_version("1.0.1", "1.0.0").unwrap());
|
||||
assert!(!checker.is_newer_version("1.0.0", "1.0.0").unwrap());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_get_current_version() {
|
||||
let version = get_current_version();
|
||||
@@ -428,4 +330,21 @@ mod tests {
|
||||
|
||||
println!("✅ VersionInfo tests passed");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_version_functions_integration() {
|
||||
// Test that version functions from version.rs work correctly
|
||||
assert_eq!(version::clean_version("refs/tags/1.0.0-alpha.17"), "1.0.0-alpha.17");
|
||||
assert_eq!(version::clean_version("v1.0.0"), "1.0.0");
|
||||
|
||||
// Test version comparison
|
||||
assert!(version::is_newer_version("1.0.0", "1.0.1").unwrap());
|
||||
assert!(!version::is_newer_version("1.0.1", "1.0.0").unwrap());
|
||||
|
||||
// Test version parsing using parse_version
|
||||
assert_eq!(version::parse_version("1.0.0").unwrap(), (1, 0, 0, None));
|
||||
assert_eq!(version::parse_version("2.1.3-alpha.1").unwrap(), (2, 1, 3, Some("alpha.1".to_string())));
|
||||
|
||||
println!("✅ Version functions integration tests passed");
|
||||
}
|
||||
}
|
||||
|
||||
+351
-2
@@ -1,13 +1,362 @@
|
||||
use shadow_rs::shadow;
|
||||
use std::process::Command;
|
||||
|
||||
shadow!(build);
|
||||
|
||||
type VersionParseResult = Result<(u32, u32, u32, Option<String>), Box<dyn std::error::Error>>;
|
||||
|
||||
#[allow(clippy::const_is_empty)]
|
||||
pub fn get_version() -> String {
|
||||
// 获取最新的 tag
|
||||
if let Ok(latest_tag) = get_latest_tag() {
|
||||
// 检查当前 commit 是否比最新 tag 更新
|
||||
if is_head_newer_than_tag(&latest_tag) {
|
||||
// 如果当前 commit 更新,则提升版本号
|
||||
if let Ok(new_version) = increment_version(&latest_tag) {
|
||||
return format!("refs/tags/{new_version}");
|
||||
}
|
||||
}
|
||||
|
||||
// 如果当前 commit 就是最新 tag,或者版本提升失败,返回当前 tag
|
||||
return format!("refs/tags/{latest_tag}");
|
||||
}
|
||||
|
||||
// 如果没有 tag,使用原来的逻辑
|
||||
if !build::TAG.is_empty() {
|
||||
build::TAG.to_string()
|
||||
format!("refs/tags/{}", build::TAG)
|
||||
} else if !build::SHORT_COMMIT.is_empty() {
|
||||
format!("@{}", build::SHORT_COMMIT)
|
||||
} else {
|
||||
build::PKG_VERSION.to_string()
|
||||
format!("refs/tags/{}", build::PKG_VERSION)
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取最新的 git tag
|
||||
fn get_latest_tag() -> Result<String, Box<dyn std::error::Error>> {
|
||||
let output = Command::new("git").args(["describe", "--tags", "--abbrev=0"]).output()?;
|
||||
|
||||
if output.status.success() {
|
||||
let tag = String::from_utf8(output.stdout)?;
|
||||
Ok(tag.trim().to_string())
|
||||
} else {
|
||||
Err("Failed to get latest tag".into())
|
||||
}
|
||||
}
|
||||
|
||||
/// 检查当前 HEAD 是否比指定的 tag 更新
|
||||
fn is_head_newer_than_tag(tag: &str) -> bool {
|
||||
let output = Command::new("git")
|
||||
.args(["merge-base", "--is-ancestor", tag, "HEAD"])
|
||||
.output();
|
||||
|
||||
match output {
|
||||
Ok(result) => result.status.success(),
|
||||
Err(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// 提升版本号(增加 patch 版本)
|
||||
fn increment_version(version: &str) -> Result<String, Box<dyn std::error::Error>> {
|
||||
// 解析版本号,例如 "1.0.0-alpha.19" -> (1, 0, 0, Some("alpha.19"))
|
||||
let (major, minor, patch, pre_release) = parse_version(version)?;
|
||||
|
||||
// 如果有预发布标识符,则增加预发布版本号
|
||||
if let Some(pre) = pre_release {
|
||||
if let Some(new_pre) = increment_pre_release(&pre) {
|
||||
return Ok(format!("{major}.{minor}.{patch}-{new_pre}"));
|
||||
}
|
||||
}
|
||||
|
||||
// 否则增加 patch 版本号
|
||||
Ok(format!("{major}.{minor}.{}", patch + 1))
|
||||
}
|
||||
|
||||
/// 解析版本号
|
||||
pub fn parse_version(version: &str) -> VersionParseResult {
|
||||
let parts: Vec<&str> = version.split('-').collect();
|
||||
let base_version = parts[0];
|
||||
let pre_release = if parts.len() > 1 { Some(parts[1..].join("-")) } else { None };
|
||||
|
||||
let version_parts: Vec<&str> = base_version.split('.').collect();
|
||||
if version_parts.len() < 3 {
|
||||
return Err("Invalid version format".into());
|
||||
}
|
||||
|
||||
let major: u32 = version_parts[0].parse()?;
|
||||
let minor: u32 = version_parts[1].parse()?;
|
||||
let patch: u32 = version_parts[2].parse()?;
|
||||
|
||||
Ok((major, minor, patch, pre_release))
|
||||
}
|
||||
|
||||
/// 增加预发布版本号
|
||||
fn increment_pre_release(pre_release: &str) -> Option<String> {
|
||||
// 处理形如 "alpha.19" 的预发布版本
|
||||
let parts: Vec<&str> = pre_release.split('.').collect();
|
||||
if parts.len() == 2 {
|
||||
if let Ok(num) = parts[1].parse::<u32>() {
|
||||
return Some(format!("{}.{}", parts[0], num + 1));
|
||||
}
|
||||
}
|
||||
|
||||
// 处理形如 "alpha19" 的预发布版本
|
||||
if let Some(pos) = pre_release.rfind(|c: char| c.is_alphabetic()) {
|
||||
let prefix = &pre_release[..=pos];
|
||||
let suffix = &pre_release[pos + 1..];
|
||||
if let Ok(num) = suffix.parse::<u32>() {
|
||||
return Some(format!("{prefix}{}", num + 1));
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// Clean version string - removes common prefixes
|
||||
pub fn clean_version(version: &str) -> String {
|
||||
version
|
||||
.trim()
|
||||
.trim_start_matches("refs/tags/")
|
||||
.trim_start_matches('v')
|
||||
.trim_start_matches("RELEASE.")
|
||||
.trim_start_matches('@')
|
||||
.to_string()
|
||||
}
|
||||
|
||||
/// Compare two versions to determine if the latest is newer
|
||||
pub fn is_newer_version(current: &str, latest: &str) -> Result<bool, Box<dyn std::error::Error>> {
|
||||
// Clean version numbers, remove prefixes like "v", "RELEASE.", etc.
|
||||
let current_clean = clean_version(current);
|
||||
let latest_clean = clean_version(latest);
|
||||
|
||||
// If versions are the same, no update is needed
|
||||
if current_clean == latest_clean {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
// Try semantic version comparison using parse_version
|
||||
match (parse_version(¤t_clean), parse_version(&latest_clean)) {
|
||||
(Ok(current_parts), Ok(latest_parts)) => Ok(compare_version_parts(¤t_parts, &latest_parts)),
|
||||
(Err(_), _) | (_, Err(_)) => {
|
||||
// If semantic version comparison fails, use string comparison
|
||||
Ok(latest_clean > current_clean)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Compare two version parts tuples (major, minor, patch, pre_release)
|
||||
fn compare_version_parts(current: &(u32, u32, u32, Option<String>), latest: &(u32, u32, u32, Option<String>)) -> bool {
|
||||
let (cur_major, cur_minor, cur_patch, cur_pre) = current;
|
||||
let (lat_major, lat_minor, lat_patch, lat_pre) = latest;
|
||||
|
||||
// Compare major version
|
||||
if lat_major != cur_major {
|
||||
return lat_major > cur_major;
|
||||
}
|
||||
|
||||
// Compare minor version
|
||||
if lat_minor != cur_minor {
|
||||
return lat_minor > cur_minor;
|
||||
}
|
||||
|
||||
// Compare patch version
|
||||
if lat_patch != cur_patch {
|
||||
return lat_patch > cur_patch;
|
||||
}
|
||||
|
||||
// Compare pre-release versions
|
||||
match (cur_pre, lat_pre) {
|
||||
(None, None) => false, // Same version
|
||||
(Some(_), None) => true, // Pre-release < release
|
||||
(None, Some(_)) => false, // Release > pre-release
|
||||
(Some(cur_pre), Some(lat_pre)) => {
|
||||
// Both are pre-release, compare them
|
||||
compare_pre_release(cur_pre, lat_pre)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Compare pre-release versions
|
||||
fn compare_pre_release(current: &str, latest: &str) -> bool {
|
||||
// Split by dots and compare each part
|
||||
let current_parts: Vec<&str> = current.split('.').collect();
|
||||
let latest_parts: Vec<&str> = latest.split('.').collect();
|
||||
|
||||
for (cur_part, lat_part) in current_parts.iter().zip(latest_parts.iter()) {
|
||||
// Try to parse as numbers first
|
||||
match (cur_part.parse::<u32>(), lat_part.parse::<u32>()) {
|
||||
(Ok(cur_num), Ok(lat_num)) => {
|
||||
if cur_num != lat_num {
|
||||
return lat_num > cur_num;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// If not numbers, compare as strings
|
||||
if cur_part != lat_part {
|
||||
return lat_part > cur_part;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If all compared parts are equal, longer version is newer
|
||||
latest_parts.len() > current_parts.len()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_parse_version() {
|
||||
// 测试标准版本解析
|
||||
let (major, minor, patch, pre_release) = parse_version("1.0.0").unwrap();
|
||||
assert_eq!(major, 1);
|
||||
assert_eq!(minor, 0);
|
||||
assert_eq!(patch, 0);
|
||||
assert_eq!(pre_release, None);
|
||||
|
||||
// 测试预发布版本解析
|
||||
let (major, minor, patch, pre_release) = parse_version("1.0.0-alpha.19").unwrap();
|
||||
assert_eq!(major, 1);
|
||||
assert_eq!(minor, 0);
|
||||
assert_eq!(patch, 0);
|
||||
assert_eq!(pre_release, Some("alpha.19".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_increment_pre_release() {
|
||||
// 测试 alpha.19 -> alpha.20
|
||||
assert_eq!(increment_pre_release("alpha.19"), Some("alpha.20".to_string()));
|
||||
|
||||
// 测试 beta.5 -> beta.6
|
||||
assert_eq!(increment_pre_release("beta.5"), Some("beta.6".to_string()));
|
||||
|
||||
// 测试无法解析的情况
|
||||
assert_eq!(increment_pre_release("unknown"), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_increment_version() {
|
||||
// 测试预发布版本递增
|
||||
assert_eq!(increment_version("1.0.0-alpha.19").unwrap(), "1.0.0-alpha.20");
|
||||
|
||||
// 测试标准版本递增
|
||||
assert_eq!(increment_version("1.0.0").unwrap(), "1.0.1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_version_format() {
|
||||
// 测试版本格式是否以 refs/tags/ 开头
|
||||
let version = get_version();
|
||||
assert!(version.starts_with("refs/tags/") || version.starts_with("@"));
|
||||
|
||||
// 如果是 refs/tags/ 格式,应该包含版本号
|
||||
if let Some(version_part) = version.strip_prefix("refs/tags/") {
|
||||
assert!(!version_part.is_empty());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_current_version_output() {
|
||||
// 显示当前版本输出
|
||||
let version = get_version();
|
||||
println!("Current version: {version}");
|
||||
|
||||
// 验证版本格式
|
||||
assert!(version.starts_with("refs/tags/") || version.starts_with("@"));
|
||||
|
||||
// 如果是 refs/tags/ 格式,验证版本号不为空
|
||||
if let Some(version_part) = version.strip_prefix("refs/tags/") {
|
||||
assert!(!version_part.is_empty());
|
||||
println!("Version part: {version_part}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_clean_version() {
|
||||
assert_eq!(clean_version("v1.0.0"), "1.0.0");
|
||||
assert_eq!(clean_version("RELEASE.1.0.0"), "1.0.0");
|
||||
assert_eq!(clean_version("@1.0.0"), "1.0.0");
|
||||
assert_eq!(clean_version("1.0.0"), "1.0.0");
|
||||
assert_eq!(clean_version("refs/tags/1.0.0-alpha.17"), "1.0.0-alpha.17");
|
||||
assert_eq!(clean_version("refs/tags/v1.0.0"), "1.0.0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_newer_version() {
|
||||
// Test semantic version comparison
|
||||
assert!(is_newer_version("1.0.0", "1.0.1").unwrap());
|
||||
assert!(is_newer_version("1.0.0", "1.1.0").unwrap());
|
||||
assert!(is_newer_version("1.0.0", "2.0.0").unwrap());
|
||||
assert!(!is_newer_version("1.0.1", "1.0.0").unwrap());
|
||||
assert!(!is_newer_version("1.0.0", "1.0.0").unwrap());
|
||||
|
||||
// Test version comparison with pre-release identifiers
|
||||
assert!(is_newer_version("1.0.0-alpha.1", "1.0.0-alpha.2").unwrap());
|
||||
assert!(is_newer_version("1.0.0-alpha.17", "1.0.1").unwrap());
|
||||
assert!(is_newer_version("refs/tags/1.0.0-alpha.16", "refs/tags/1.0.0-alpha.17").unwrap());
|
||||
assert!(!is_newer_version("refs/tags/1.0.0-alpha.17", "refs/tags/1.0.0-alpha.16").unwrap());
|
||||
|
||||
// Test pre-release vs release comparison
|
||||
assert!(is_newer_version("1.0.0-alpha.1", "1.0.0").unwrap());
|
||||
assert!(is_newer_version("1.0.0-beta.1", "1.0.0").unwrap());
|
||||
assert!(!is_newer_version("1.0.0", "1.0.0-alpha.1").unwrap());
|
||||
assert!(!is_newer_version("1.0.0", "1.0.0-beta.1").unwrap());
|
||||
|
||||
// Test pre-release version ordering
|
||||
assert!(is_newer_version("1.0.0-alpha.1", "1.0.0-alpha.2").unwrap());
|
||||
assert!(is_newer_version("1.0.0-alpha.19", "1.0.0-alpha.20").unwrap());
|
||||
assert!(is_newer_version("1.0.0-alpha.1", "1.0.0-beta.1").unwrap());
|
||||
assert!(is_newer_version("1.0.0-beta.1", "1.0.0-rc.1").unwrap());
|
||||
|
||||
// Test complex pre-release versions
|
||||
assert!(is_newer_version("1.0.0-alpha.1.2", "1.0.0-alpha.1.3").unwrap());
|
||||
assert!(is_newer_version("1.0.0-alpha.1", "1.0.0-alpha.1.1").unwrap());
|
||||
assert!(!is_newer_version("1.0.0-alpha.1.3", "1.0.0-alpha.1.2").unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_compare_version_parts() {
|
||||
// Test basic version comparison
|
||||
assert!(compare_version_parts(&(1, 0, 0, None), &(1, 0, 1, None)));
|
||||
assert!(compare_version_parts(&(1, 0, 0, None), &(1, 1, 0, None)));
|
||||
assert!(compare_version_parts(&(1, 0, 0, None), &(2, 0, 0, None)));
|
||||
assert!(!compare_version_parts(&(1, 0, 1, None), &(1, 0, 0, None)));
|
||||
|
||||
// Test pre-release vs release
|
||||
assert!(compare_version_parts(&(1, 0, 0, Some("alpha.1".to_string())), &(1, 0, 0, None)));
|
||||
assert!(!compare_version_parts(&(1, 0, 0, None), &(1, 0, 0, Some("alpha.1".to_string()))));
|
||||
|
||||
// Test pre-release comparison
|
||||
assert!(compare_version_parts(
|
||||
&(1, 0, 0, Some("alpha.1".to_string())),
|
||||
&(1, 0, 0, Some("alpha.2".to_string()))
|
||||
));
|
||||
assert!(compare_version_parts(
|
||||
&(1, 0, 0, Some("alpha.19".to_string())),
|
||||
&(1, 0, 0, Some("alpha.20".to_string()))
|
||||
));
|
||||
assert!(compare_version_parts(
|
||||
&(1, 0, 0, Some("alpha.1".to_string())),
|
||||
&(1, 0, 0, Some("beta.1".to_string()))
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_compare_pre_release() {
|
||||
// Test numeric pre-release comparison
|
||||
assert!(compare_pre_release("alpha.1", "alpha.2"));
|
||||
assert!(compare_pre_release("alpha.19", "alpha.20"));
|
||||
assert!(!compare_pre_release("alpha.2", "alpha.1"));
|
||||
|
||||
// Test string pre-release comparison
|
||||
assert!(compare_pre_release("alpha.1", "beta.1"));
|
||||
assert!(compare_pre_release("beta.1", "rc.1"));
|
||||
assert!(!compare_pre_release("beta.1", "alpha.1"));
|
||||
|
||||
// Test complex pre-release comparison
|
||||
assert!(compare_pre_release("alpha.1.2", "alpha.1.3"));
|
||||
assert!(compare_pre_release("alpha.1", "alpha.1.1"));
|
||||
assert!(!compare_pre_release("alpha.1.3", "alpha.1.2"));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user