pub struct VersionResolver { /* private fields */ }Expand description
Resolves semantic versions from Git repository tags.
VersionResolver provides the core functionality for discovering, parsing, and
resolving semantic versions from Git tags. It handles tag discovery, version
parsing, constraint matching, and best-version selection.
§Tag Processing
The resolver automatically:
- Fetches all tags from a Git repository
- Normalizes tag names (removes
vprefixes, handles common formats) - Parses valid semantic versions (skips invalid tags)
- Sorts versions in descending order (newest first)
- Categorizes versions as stable or prerelease
§Resolution Strategy
When resolving version constraints:
- Special keywords are handled first (
latest,latest-prerelease) - Exact versions are matched with or without
vprefixes - Semantic ranges are applied using semver matching rules
- Tag names are matched exactly as fallback
- Prerelease filtering is applied based on constraint type
§Examples
§Creating from Git Repository
use ccpm::version::VersionResolver;
use ccpm::git::GitRepo;
use std::path::PathBuf;
let repo = GitRepo::new(PathBuf::from("/path/to/repo"));
let resolver = VersionResolver::from_git_tags(&repo).await?;
println!("Found {} versions", resolver.list_all().len());§Version Resolution
// Resolve various constraint types
if let Some(version) = resolver.resolve("^1.0.0")? {
println!("Caret range resolved to: {} ({})", version.tag, version.version);
}
if let Some(version) = resolver.resolve("latest")? {
println!("Latest stable: {} (prerelease: {})", version.tag, version.prerelease);
}
if let Some(version) = resolver.resolve("v1.2.3")? {
println!("Exact match: {}", version.tag);
}Implementations§
Source§impl VersionResolver
impl VersionResolver
Sourcepub fn new() -> Self
pub fn new() -> Self
Create a new empty resolver with no versions.
This constructor creates an empty resolver that contains no version information.
It’s primarily useful for testing or as a starting point before adding versions
manually. For normal usage, prefer from_git_tags which
populates the resolver from a Git repository.
§Examples
use ccpm::version::VersionResolver;
let resolver = VersionResolver::new();
assert_eq!(resolver.list_all().len(), 0);
assert!(resolver.get_latest().is_none());Create a resolver by discovering and parsing tags from a Git repository.
This method performs the complete tag discovery and parsing workflow:
- Fetch tags: Retrieve all Git tags from the repository
- Parse versions: Attempt to parse each tag as a semantic version
- Filter valid: Keep only tags that parse successfully
- Sort versions: Order by semantic version (newest first)
- Detect prereleases: Identify versions with prerelease components
§Arguments
repo- TheGitRepoinstance to discover tags from
§Returns
Returns Ok(VersionResolver) with parsed versions, or Err if Git
operations fail. Individual tag parsing failures are silently ignored.
§Tag Parsing Rules
- Common prefixes (
v,V) are automatically stripped - Invalid semantic versions are skipped (not included in resolver)
- Valid versions are sorted in descending order
- Prerelease status is detected from version components
§Examples
use ccpm::version::VersionResolver;
use ccpm::git::GitRepo;
use std::path::PathBuf;
let repo = GitRepo::new(PathBuf::from("/path/to/repo"));
let resolver = VersionResolver::from_git_tags(&repo).await?;
println!("Discovered {} valid versions", resolver.list_all().len());
if let Some(latest) = resolver.get_latest() {
println!("Latest version: {} ({})", latest.tag, latest.version);
}§Error Handling
This method returns errors for Git operations (repository access, tag listing) but handles individual tag parsing failures gracefully by skipping invalid tags.
Sourcepub fn resolve(&self, requirement: &str) -> Result<Option<VersionInfo>>
pub fn resolve(&self, requirement: &str) -> Result<Option<VersionInfo>>
Resolve a version requirement string to a specific version from available tags.
This method applies version constraint logic to find the best matching version from the resolver’s collection of parsed Git tags. It supports various constraint formats and applies appropriate matching rules for each type.
§Constraint Resolution Order
- Special keywords:
"latest","latest-prerelease"are handled first - Exact versions: Direct semantic version matches (with/without
vprefix) - Version requirements: Semver ranges like
"^1.0.0","~1.2.0" - Tag names: Exact tag string matching as fallback
§Arguments
requirement- The version constraint string to resolve
§Returns
Returns Ok(Some(VersionInfo)) if a matching version is found, Ok(None)
if no version satisfies the requirement, or Err for invalid requirements.
§Prerelease Handling
- Default behavior: Prereleases are excluded from semver range matching
- Explicit inclusion: Use
"latest-prerelease"to include prereleases - Exact matches: Direct version/tag matches include prereleases
§Examples
use ccpm::version::VersionResolver;
use ccpm::git::GitRepo;
use std::path::PathBuf;
let repo = GitRepo::new(PathBuf::from("/path/to/repo"));
let resolver = VersionResolver::from_git_tags(&repo).await?;
// Special keywords
if let Some(version) = resolver.resolve("latest")? {
println!("Latest stable: {}", version.tag);
}
// Exact version matching
if let Some(version) = resolver.resolve("1.2.3")? {
println!("Found exact version: {}", version.tag);
}
// Semver ranges
if let Some(version) = resolver.resolve("^1.0.0")? {
println!("Compatible version: {} ({})", version.tag, version.version);
}
// Tag name matching
if let Some(version) = resolver.resolve("v1.0.0-beta.1")? {
println!("Tag match: {}", version.tag);
}§Resolution Precedence
When multiple versions could match:
- Highest version wins: Newer semantic versions are preferred
- Stable over prerelease: Stable versions preferred unless prereleases explicitly allowed
- First match for tags: Tag name matching returns the first occurrence
Sourcepub fn get_latest(&self) -> Option<VersionInfo>
pub fn get_latest(&self) -> Option<VersionInfo>
Get the latest version including prereleases.
This method returns the absolute newest version from the resolver’s collection, including prerelease versions. Since versions are sorted in descending order, this simply returns the first version in the list.
§Returns
Returns Some(VersionInfo) with the highest version, or None if no versions
are available in the resolver.
§Prerelease Inclusion
Unlike get_latest_stable, this method includes
prerelease versions in consideration. If the highest version happens to be
a prerelease (e.g., 2.0.0-beta.1 when 1.9.0 is the latest stable),
the prerelease version will be returned.
§Examples
use ccpm::version::VersionResolver;
use ccpm::git::GitRepo;
use std::path::PathBuf;
let repo = GitRepo::new(PathBuf::from("/path/to/repo"));
let resolver = VersionResolver::from_git_tags(&repo).await?;
if let Some(latest) = resolver.get_latest() {
println!("Absolute latest: {} (prerelease: {})",
latest.tag, latest.prerelease);
} else {
println!("No versions found in repository");
}§Use Cases
This method is useful when:
- You want the cutting-edge version regardless of stability
- Implementing
latest-prereleaseconstraint resolution - Analyzing the most recent development activity
Sourcepub fn get_latest_stable(&self) -> Option<VersionInfo>
pub fn get_latest_stable(&self) -> Option<VersionInfo>
Get the latest stable version excluding prereleases.
This method finds the newest version that doesn’t contain prerelease identifiers
(such as -alpha, -beta, -rc). It’s the preferred method for production
environments where stability is prioritized over cutting-edge features.
§Returns
Returns Some(VersionInfo) with the highest stable version, or None if no
stable versions are available (only prereleases exist).
§Stability Definition
A version is considered stable if its prerelease component is empty. This means:
1.0.0is stable1.0.0-beta.1is not stable (has prerelease suffix)1.0.0+build.123is stable (build metadata doesn’t affect stability)
§Examples
use ccpm::version::VersionResolver;
use ccpm::git::GitRepo;
use std::path::PathBuf;
let repo = GitRepo::new(PathBuf::from("/path/to/repo"));
let resolver = VersionResolver::from_git_tags(&repo).await?;
match resolver.get_latest_stable() {
Some(stable) => {
println!("Latest stable version: {}", stable.tag);
assert!(!stable.prerelease); // Always false for stable versions
}
None => println!("No stable versions found (only prereleases available)"),
}§Comparison with get_latest()
let latest = resolver.get_latest();
let stable = resolver.get_latest_stable();
// Latest might be a prerelease version
// Stable will always be a non-prerelease version (or None)
if let (Some(l), Some(s)) = (latest, stable) {
if l.version > s.version {
println!("Newest version {} is a prerelease", l.tag);
println!("Latest stable version is {}", s.tag);
}
}§Use Cases
This method is ideal for:
- Production dependency resolution
- Implementing
"latest"constraint resolution - Default version selection in package managers
- Stable release identification
Sourcepub fn list_all(&self) -> Vec<VersionInfo>
pub fn list_all(&self) -> Vec<VersionInfo>
List all versions discovered from Git tags.
This method returns a complete list of all successfully parsed versions from the Git repository, including both stable and prerelease versions. The list is sorted in descending order by semantic version (newest first).
§Returns
Returns Vec<VersionInfo> containing all parsed versions. The vector may be
empty if no valid semantic versions were found in the repository tags.
§Sorting Order
Versions are sorted by semantic version precedence in descending order:
- Higher major versions first (e.g.,
2.0.0before1.9.0) - Higher minor versions within same major (e.g.,
1.5.0before1.2.0) - Higher patch versions within same minor (e.g.,
1.2.3before1.2.1) - Release versions before prereleases (e.g.,
1.0.0before1.0.0-beta.1)
§Examples
use ccpm::version::VersionResolver;
use ccpm::git::GitRepo;
use std::path::PathBuf;
let repo = GitRepo::new(PathBuf::from("/path/to/repo"));
let resolver = VersionResolver::from_git_tags(&repo).await?;
let all_versions = resolver.list_all();
println!("Found {} versions:", all_versions.len());
for (i, version) in all_versions.iter().enumerate() {
let status = if version.prerelease { "prerelease" } else { "stable" };
println!(" {}. {} ({}) - {}", i + 1, version.tag, version.version, status);
}§Filtering and Analysis
let all_versions = resolver.list_all();
// Count prereleases vs stable
let prerelease_count = all_versions.iter().filter(|v| v.prerelease).count();
let stable_count = all_versions.len() - prerelease_count;
println!("Stable versions: {}, Prereleases: {}", stable_count, prerelease_count);
// Find versions in a specific range
let v1_versions: Vec<_> = all_versions.iter()
.filter(|v| v.version.major == 1)
.collect();
println!("Found {} versions in v1.x.x series", v1_versions.len());§Use Cases
This method is useful for:
- Version analysis and reporting
- Building version selection interfaces
- Debugging version resolution issues
- Implementing custom constraint logic
Sourcepub fn list_stable(&self) -> Vec<VersionInfo>
pub fn list_stable(&self) -> Vec<VersionInfo>
List only stable versions excluding prereleases.
This method filters the complete version list to include only versions without prerelease components. It’s useful for scenarios where you need to work with production-ready versions only.
§Returns
Returns Vec<VersionInfo> containing only stable versions, sorted in descending
order. The vector may be empty if no stable versions exist (only prereleases).
§Filtering Criteria
A version is included if:
- Its prerelease component is empty (no
-alpha,-beta,-rcsuffixes) - It parses as a valid semantic version
- It was successfully extracted from a Git tag
§Examples
use ccpm::version::VersionResolver;
use ccpm::git::GitRepo;
use std::path::PathBuf;
let repo = GitRepo::new(PathBuf::from("/path/to/repo"));
let resolver = VersionResolver::from_git_tags(&repo).await?;
let stable_versions = resolver.list_stable();
println!("Found {} stable versions:", stable_versions.len());
for version in stable_versions {
println!(" {} ({})", version.tag, version.version);
assert!(!version.prerelease); // Guaranteed to be false
}§Comparison with All Versions
let all_versions = resolver.list_all();
let stable_versions = resolver.list_stable();
println!("Total versions: {}", all_versions.len());
println!("Stable versions: {}", stable_versions.len());
println!("Prerelease versions: {}", all_versions.len() - stable_versions.len());
if stable_versions.len() < all_versions.len() {
println!("Repository contains prerelease versions");
}§Use Cases
This method is particularly useful for:
- Production environment version selection
- Conservative update strategies
- Compliance requirements that exclude prereleases
- User interfaces that hide development versions by default
Sourcepub fn has_version(&self, version: &str) -> bool
pub fn has_version(&self, version: &str) -> bool
Check if a specific version constraint can be resolved.
This method tests whether a given version constraint string can be successfully resolved against the available versions in this resolver. It’s a convenience method that combines resolution and existence checking.
§Arguments
version- The version constraint string to test
§Returns
Returns true if the version constraint resolves to an actual version,
false if no matching version is found or if resolution fails.
§Resolution Types Tested
This method can verify existence of:
- Exact versions:
"1.0.0","v1.2.3" - Version ranges:
"^1.0.0","~1.2.0",">=1.0.0" - Special keywords:
"latest","latest-prerelease" - Tag names: Exact Git tag matches
§Examples
use ccpm::version::VersionResolver;
use ccpm::git::GitRepo;
use std::path::PathBuf;
let repo = GitRepo::new(PathBuf::from("/path/to/repo"));
let resolver = VersionResolver::from_git_tags(&repo).await?;
// Check if specific versions exist
if resolver.has_version("1.0.0") {
println!("Version 1.0.0 is available");
}
if resolver.has_version("^1.0.0") {
println!("Compatible versions with 1.0.0 exist");
}
if resolver.has_version("latest") {
println!("At least one stable version exists");
}
// This will likely return false unless you have this exact tag
if resolver.has_version("v99.99.99") {
println!("Unlikely version found!");
} else {
println!("Version 99.99.99 not found (as expected)");
}§Validation Before Resolution
let constraint = "^2.0.0";
if resolver.has_version(constraint) {
// Safe to resolve - we know it will succeed
let version = resolver.resolve(constraint)?.unwrap();
println!("Resolved {} to {}", constraint, version.tag);
} else {
println!("No versions satisfy constraint: {}", constraint);
}§Error Handling
This method handles resolution errors gracefully by returning false rather
than propagating errors. This makes it safe to use for validation without
extensive error handling.
§Use Cases
This method is useful for:
- Validating user input before processing
- Pre-flight checks in dependency resolution
- Conditional logic based on version availability
- User interface validation and feedback