upd-cli 0.0.26__tar.gz → 0.0.27__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {upd_cli-0.0.26 → upd_cli-0.0.27}/CHANGELOG.md +8 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/Cargo.lock +1 -1
- {upd_cli-0.0.26 → upd_cli-0.0.27}/Cargo.toml +1 -1
- {upd_cli-0.0.26 → upd_cli-0.0.27}/PKG-INFO +1 -1
- {upd_cli-0.0.26 → upd_cli-0.0.27}/src/align.rs +2 -10
- {upd_cli-0.0.26 → upd_cli-0.0.27}/src/registry/pypi.rs +3 -0
- upd_cli-0.0.27/src/version/mod.rs +105 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/src/version/pep440.rs +3 -0
- upd_cli-0.0.26/src/version/mod.rs +0 -55
- {upd_cli-0.0.26 → upd_cli-0.0.27}/.mise.toml +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/.pre-commit-config.yaml +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/.pre-commit-hooks.yaml +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/.rumdl.toml +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/LICENSE +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/Makefile +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/README.md +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/assets/logo-wide.svg +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/assets/logo.svg +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/pyproject.toml +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/python/upd_cli/__init__.py +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/python/upd_cli/__main__.py +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/python/upd_cli/py.typed +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/rust-toolchain.toml +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/src/audit.rs +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/src/cache.rs +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/src/cli.rs +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/src/config.rs +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/src/interactive.rs +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/src/lib.rs +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/src/lockfile.rs +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/src/main.rs +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/src/registry/crates_io.rs +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/src/registry/github_releases.rs +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/src/registry/go_proxy.rs +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/src/registry/mock.rs +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/src/registry/mod.rs +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/src/registry/npm.rs +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/src/registry/nuget.rs +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/src/registry/rubygems.rs +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/src/registry/terraform.rs +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/src/registry/utils.rs +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/src/updater/cargo_toml.rs +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/src/updater/csproj.rs +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/src/updater/gemfile.rs +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/src/updater/github_actions.rs +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/src/updater/go_mod.rs +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/src/updater/mise.rs +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/src/updater/mod.rs +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/src/updater/package_json.rs +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/src/updater/pre_commit.rs +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/src/updater/pyproject.rs +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/src/updater/requirements.rs +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/src/updater/terraform.rs +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/src/version/semver_util.rs +0 -0
- {upd_cli-0.0.26 → upd_cli-0.0.27}/vership.toml +0 -0
|
@@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
|
|
10
|
+
|
|
11
|
+
## [0.0.27](https://github.com/rvben/upd/compare/v0.0.26...v0.0.27) - 2026-04-15
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- **align**: use pep440_rs for Python stable-version check ([7f132b3](https://github.com/rvben/upd/commit/7f132b351cdd9225a31df96d2a421c8c42926987))
|
|
16
|
+
- **version**: use PEP 440 release segments for precision matching ([fff041d](https://github.com/rvben/upd/commit/fff041d2d2e9508f117012a6bfc857ee57e5cd20))
|
|
17
|
+
|
|
10
18
|
## [0.0.26](https://github.com/rvben/upd/compare/v0.0.25...v0.0.26) - 2026-04-15
|
|
11
19
|
|
|
12
20
|
### Fixed
|
|
@@ -8,6 +8,7 @@ use crate::updater::{
|
|
|
8
8
|
Lang, MiseUpdater, PackageJsonUpdater, ParsedDependency, PreCommitUpdater, PyProjectUpdater,
|
|
9
9
|
RequirementsUpdater, TerraformUpdater, Updater,
|
|
10
10
|
};
|
|
11
|
+
use crate::version::is_stable_pep440;
|
|
11
12
|
use anyhow::Result;
|
|
12
13
|
use std::collections::HashMap;
|
|
13
14
|
use std::path::{Path, PathBuf};
|
|
@@ -170,16 +171,7 @@ fn find_highest_version(occurrences: &[PackageOccurrence], lang: Lang) -> Option
|
|
|
170
171
|
/// Check if a version is stable (not a pre-release)
|
|
171
172
|
fn is_stable_version(version: &str, lang: Lang) -> bool {
|
|
172
173
|
match lang {
|
|
173
|
-
Lang::Python =>
|
|
174
|
-
// Python pre-release indicators: a, b, rc, alpha, beta, dev
|
|
175
|
-
let v = version.to_lowercase();
|
|
176
|
-
!v.contains("a")
|
|
177
|
-
&& !v.contains("b")
|
|
178
|
-
&& !v.contains("rc")
|
|
179
|
-
&& !v.contains("alpha")
|
|
180
|
-
&& !v.contains("beta")
|
|
181
|
-
&& !v.contains("dev")
|
|
182
|
-
}
|
|
174
|
+
Lang::Python => is_stable_pep440(version),
|
|
183
175
|
Lang::Node | Lang::Rust | Lang::Go | Lang::DotNet => {
|
|
184
176
|
// Semver pre-release indicator: hyphen followed by identifier
|
|
185
177
|
!version.contains('-')
|
|
@@ -896,6 +896,9 @@ mod tests {
|
|
|
896
896
|
fn test_stable_version_detection() {
|
|
897
897
|
assert!(PyPiRegistry::is_stable_version("1.0.0"));
|
|
898
898
|
assert!(PyPiRegistry::is_stable_version("2.31.0"));
|
|
899
|
+
// Post-releases are stable releases that fix packaging issues
|
|
900
|
+
assert!(PyPiRegistry::is_stable_version("1.0.0.post1"));
|
|
901
|
+
assert!(PyPiRegistry::is_stable_version("2.1117.0.post1"));
|
|
899
902
|
assert!(!PyPiRegistry::is_stable_version("1.0.0a1"));
|
|
900
903
|
assert!(!PyPiRegistry::is_stable_version("1.0.0b2"));
|
|
901
904
|
assert!(!PyPiRegistry::is_stable_version("1.0.0rc1"));
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
pub mod pep440;
|
|
2
|
+
pub mod semver_util;
|
|
3
|
+
|
|
4
|
+
pub use pep440::is_stable_pep440;
|
|
5
|
+
pub use semver_util::is_stable_semver;
|
|
6
|
+
|
|
7
|
+
/// Match the precision of a new version to the original version's precision.
|
|
8
|
+
///
|
|
9
|
+
/// For PEP 440 versions (Python), the release segment length is determined by
|
|
10
|
+
/// parsing with `pep440_rs`, so post-release (`.post1`), dev (`.dev0`), and
|
|
11
|
+
/// pre-release (`a1`, `b1`, `rc1`) suffixes are not counted as release segments
|
|
12
|
+
/// and are preserved when the release segment count matches.
|
|
13
|
+
///
|
|
14
|
+
/// For other version schemes (semver, Go, Ruby…) that `pep440_rs` cannot parse,
|
|
15
|
+
/// the function falls back to counting dot-separated segments.
|
|
16
|
+
///
|
|
17
|
+
/// Examples:
|
|
18
|
+
/// - ("2.0", "3.0.5") → "3.0"
|
|
19
|
+
/// - ("2.0.0", "3.0.5") → "3.0.5"
|
|
20
|
+
/// - ("2", "3.0.5") → "3"
|
|
21
|
+
/// - ("1.2.3.4", "5.6.7.8") → "5.6.7.8" (preserve all parts)
|
|
22
|
+
/// - ("2.1117.0", "2.1117.0.post1") → "2.1117.0.post1" (post-release preserved)
|
|
23
|
+
pub fn match_version_precision(original: &str, new_version: &str) -> String {
|
|
24
|
+
use pep440_rs::Version;
|
|
25
|
+
|
|
26
|
+
// Try PEP 440 parsing first; `.release()` returns only the numeric
|
|
27
|
+
// release tuple, correctly excluding pre/post/dev labels.
|
|
28
|
+
if let (Ok(orig), Ok(new)) = (original.parse::<Version>(), new_version.parse::<Version>()) {
|
|
29
|
+
let orig_len = orig.release().len();
|
|
30
|
+
let new_len = new.release().len();
|
|
31
|
+
|
|
32
|
+
return if orig_len >= new_len {
|
|
33
|
+
// Same or fewer release segments — keep the full new version string
|
|
34
|
+
// (including any post/pre/dev suffix) as written by the caller.
|
|
35
|
+
new_version.to_string()
|
|
36
|
+
} else {
|
|
37
|
+
// More release segments than original — truncate to original precision.
|
|
38
|
+
// Any post/pre/dev suffix on the new version is intentionally dropped
|
|
39
|
+
// since it belongs to a more specific release than we're tracking.
|
|
40
|
+
new.release()[..orig_len]
|
|
41
|
+
.iter()
|
|
42
|
+
.map(|n| n.to_string())
|
|
43
|
+
.collect::<Vec<_>>()
|
|
44
|
+
.join(".")
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Fallback for non-PEP-440 versions (semver, Go modules, etc.)
|
|
49
|
+
let original_parts: Vec<&str> = original.split('.').collect();
|
|
50
|
+
let new_parts: Vec<&str> = new_version.split('.').collect();
|
|
51
|
+
let precision = original_parts.len();
|
|
52
|
+
|
|
53
|
+
if precision >= new_parts.len() {
|
|
54
|
+
new_version.to_string()
|
|
55
|
+
} else {
|
|
56
|
+
new_parts[..precision].join(".")
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
#[cfg(test)]
|
|
61
|
+
mod tests {
|
|
62
|
+
use super::*;
|
|
63
|
+
|
|
64
|
+
#[test]
|
|
65
|
+
fn test_match_version_precision() {
|
|
66
|
+
// Major.minor only
|
|
67
|
+
assert_eq!(match_version_precision("2.0", "3.0.5"), "3.0");
|
|
68
|
+
assert_eq!(match_version_precision("2.8", "3.1.2"), "3.1");
|
|
69
|
+
|
|
70
|
+
// Full precision
|
|
71
|
+
assert_eq!(match_version_precision("2.0.0", "3.0.5"), "3.0.5");
|
|
72
|
+
assert_eq!(match_version_precision("1.2.3", "4.5.6"), "4.5.6");
|
|
73
|
+
|
|
74
|
+
// Major only
|
|
75
|
+
assert_eq!(match_version_precision("2", "3.0.5"), "3");
|
|
76
|
+
|
|
77
|
+
// New version has fewer parts than original (edge case)
|
|
78
|
+
assert_eq!(match_version_precision("2.0.0", "3.0"), "3.0");
|
|
79
|
+
assert_eq!(match_version_precision("2.0.0.0", "3.0.5"), "3.0.5");
|
|
80
|
+
|
|
81
|
+
// Same precision
|
|
82
|
+
assert_eq!(match_version_precision("1.0.0", "2.0.0"), "2.0.0");
|
|
83
|
+
|
|
84
|
+
// PEP 440 post-release suffix must be preserved when release precision matches
|
|
85
|
+
assert_eq!(
|
|
86
|
+
match_version_precision("2.1117.0", "2.1117.0.post1"),
|
|
87
|
+
"2.1117.0.post1"
|
|
88
|
+
);
|
|
89
|
+
assert_eq!(
|
|
90
|
+
match_version_precision("1.0.0", "1.0.0.post2"),
|
|
91
|
+
"1.0.0.post2"
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
// PEP 440 pre-release labels (no dot separator) are also preserved
|
|
95
|
+
assert_eq!(match_version_precision("2.0.0", "2.0.1a1"), "2.0.1a1");
|
|
96
|
+
assert_eq!(match_version_precision("2.0.0", "2.0.1b1"), "2.0.1b1");
|
|
97
|
+
assert_eq!(match_version_precision("2.0.0", "2.0.1rc1"), "2.0.1rc1");
|
|
98
|
+
|
|
99
|
+
// PEP 440 dev releases are also preserved
|
|
100
|
+
assert_eq!(match_version_precision("2.0.0", "2.0.0.dev1"), "2.0.0.dev1");
|
|
101
|
+
|
|
102
|
+
// Truncation path: suffix is dropped when original has lower precision
|
|
103
|
+
assert_eq!(match_version_precision("2.0", "3.0.5.post1"), "3.0");
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -28,6 +28,9 @@ mod tests {
|
|
|
28
28
|
assert!(is_stable_pep440("0.1.0"));
|
|
29
29
|
assert!(is_stable_pep440("1.0"));
|
|
30
30
|
assert!(is_stable_pep440("1"));
|
|
31
|
+
// Post-releases are stable releases that fix packaging issues
|
|
32
|
+
assert!(is_stable_pep440("1.0.0.post1"));
|
|
33
|
+
assert!(is_stable_pep440("2.1117.0.post1"));
|
|
31
34
|
}
|
|
32
35
|
|
|
33
36
|
#[test]
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
pub mod pep440;
|
|
2
|
-
pub mod semver_util;
|
|
3
|
-
|
|
4
|
-
pub use pep440::is_stable_pep440;
|
|
5
|
-
pub use semver_util::is_stable_semver;
|
|
6
|
-
|
|
7
|
-
/// Match the precision of a new version to the original version's precision.
|
|
8
|
-
///
|
|
9
|
-
/// Examples:
|
|
10
|
-
/// - ("2.0", "3.0.5") → "3.0"
|
|
11
|
-
/// - ("2.0.0", "3.0.5") → "3.0.5"
|
|
12
|
-
/// - ("2", "3.0.5") → "3"
|
|
13
|
-
/// - ("1.2.3.4", "5.6.7.8") → "5.6.7.8" (preserve all parts)
|
|
14
|
-
pub fn match_version_precision(original: &str, new_version: &str) -> String {
|
|
15
|
-
let original_parts: Vec<&str> = original.split('.').collect();
|
|
16
|
-
let new_parts: Vec<&str> = new_version.split('.').collect();
|
|
17
|
-
|
|
18
|
-
// Count how many parts the original has
|
|
19
|
-
let precision = original_parts.len();
|
|
20
|
-
|
|
21
|
-
// Take the same number of parts from the new version
|
|
22
|
-
if precision >= new_parts.len() {
|
|
23
|
-
// Original has same or more precision, use full new version
|
|
24
|
-
new_version.to_string()
|
|
25
|
-
} else {
|
|
26
|
-
// Original has less precision, truncate new version
|
|
27
|
-
new_parts[..precision].join(".")
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
#[cfg(test)]
|
|
32
|
-
mod tests {
|
|
33
|
-
use super::*;
|
|
34
|
-
|
|
35
|
-
#[test]
|
|
36
|
-
fn test_match_version_precision() {
|
|
37
|
-
// Major.minor only
|
|
38
|
-
assert_eq!(match_version_precision("2.0", "3.0.5"), "3.0");
|
|
39
|
-
assert_eq!(match_version_precision("2.8", "3.1.2"), "3.1");
|
|
40
|
-
|
|
41
|
-
// Full precision
|
|
42
|
-
assert_eq!(match_version_precision("2.0.0", "3.0.5"), "3.0.5");
|
|
43
|
-
assert_eq!(match_version_precision("1.2.3", "4.5.6"), "4.5.6");
|
|
44
|
-
|
|
45
|
-
// Major only
|
|
46
|
-
assert_eq!(match_version_precision("2", "3.0.5"), "3");
|
|
47
|
-
|
|
48
|
-
// New version has fewer parts than original (edge case)
|
|
49
|
-
assert_eq!(match_version_precision("2.0.0", "3.0"), "3.0");
|
|
50
|
-
assert_eq!(match_version_precision("2.0.0.0", "3.0.5"), "3.0.5");
|
|
51
|
-
|
|
52
|
-
// Same precision
|
|
53
|
-
assert_eq!(match_version_precision("1.0.0", "2.0.0"), "2.0.0");
|
|
54
|
-
}
|
|
55
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|