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.
Files changed (55) hide show
  1. {upd_cli-0.0.26 → upd_cli-0.0.27}/CHANGELOG.md +8 -0
  2. {upd_cli-0.0.26 → upd_cli-0.0.27}/Cargo.lock +1 -1
  3. {upd_cli-0.0.26 → upd_cli-0.0.27}/Cargo.toml +1 -1
  4. {upd_cli-0.0.26 → upd_cli-0.0.27}/PKG-INFO +1 -1
  5. {upd_cli-0.0.26 → upd_cli-0.0.27}/src/align.rs +2 -10
  6. {upd_cli-0.0.26 → upd_cli-0.0.27}/src/registry/pypi.rs +3 -0
  7. upd_cli-0.0.27/src/version/mod.rs +105 -0
  8. {upd_cli-0.0.26 → upd_cli-0.0.27}/src/version/pep440.rs +3 -0
  9. upd_cli-0.0.26/src/version/mod.rs +0 -55
  10. {upd_cli-0.0.26 → upd_cli-0.0.27}/.mise.toml +0 -0
  11. {upd_cli-0.0.26 → upd_cli-0.0.27}/.pre-commit-config.yaml +0 -0
  12. {upd_cli-0.0.26 → upd_cli-0.0.27}/.pre-commit-hooks.yaml +0 -0
  13. {upd_cli-0.0.26 → upd_cli-0.0.27}/.rumdl.toml +0 -0
  14. {upd_cli-0.0.26 → upd_cli-0.0.27}/LICENSE +0 -0
  15. {upd_cli-0.0.26 → upd_cli-0.0.27}/Makefile +0 -0
  16. {upd_cli-0.0.26 → upd_cli-0.0.27}/README.md +0 -0
  17. {upd_cli-0.0.26 → upd_cli-0.0.27}/assets/logo-wide.svg +0 -0
  18. {upd_cli-0.0.26 → upd_cli-0.0.27}/assets/logo.svg +0 -0
  19. {upd_cli-0.0.26 → upd_cli-0.0.27}/pyproject.toml +0 -0
  20. {upd_cli-0.0.26 → upd_cli-0.0.27}/python/upd_cli/__init__.py +0 -0
  21. {upd_cli-0.0.26 → upd_cli-0.0.27}/python/upd_cli/__main__.py +0 -0
  22. {upd_cli-0.0.26 → upd_cli-0.0.27}/python/upd_cli/py.typed +0 -0
  23. {upd_cli-0.0.26 → upd_cli-0.0.27}/rust-toolchain.toml +0 -0
  24. {upd_cli-0.0.26 → upd_cli-0.0.27}/src/audit.rs +0 -0
  25. {upd_cli-0.0.26 → upd_cli-0.0.27}/src/cache.rs +0 -0
  26. {upd_cli-0.0.26 → upd_cli-0.0.27}/src/cli.rs +0 -0
  27. {upd_cli-0.0.26 → upd_cli-0.0.27}/src/config.rs +0 -0
  28. {upd_cli-0.0.26 → upd_cli-0.0.27}/src/interactive.rs +0 -0
  29. {upd_cli-0.0.26 → upd_cli-0.0.27}/src/lib.rs +0 -0
  30. {upd_cli-0.0.26 → upd_cli-0.0.27}/src/lockfile.rs +0 -0
  31. {upd_cli-0.0.26 → upd_cli-0.0.27}/src/main.rs +0 -0
  32. {upd_cli-0.0.26 → upd_cli-0.0.27}/src/registry/crates_io.rs +0 -0
  33. {upd_cli-0.0.26 → upd_cli-0.0.27}/src/registry/github_releases.rs +0 -0
  34. {upd_cli-0.0.26 → upd_cli-0.0.27}/src/registry/go_proxy.rs +0 -0
  35. {upd_cli-0.0.26 → upd_cli-0.0.27}/src/registry/mock.rs +0 -0
  36. {upd_cli-0.0.26 → upd_cli-0.0.27}/src/registry/mod.rs +0 -0
  37. {upd_cli-0.0.26 → upd_cli-0.0.27}/src/registry/npm.rs +0 -0
  38. {upd_cli-0.0.26 → upd_cli-0.0.27}/src/registry/nuget.rs +0 -0
  39. {upd_cli-0.0.26 → upd_cli-0.0.27}/src/registry/rubygems.rs +0 -0
  40. {upd_cli-0.0.26 → upd_cli-0.0.27}/src/registry/terraform.rs +0 -0
  41. {upd_cli-0.0.26 → upd_cli-0.0.27}/src/registry/utils.rs +0 -0
  42. {upd_cli-0.0.26 → upd_cli-0.0.27}/src/updater/cargo_toml.rs +0 -0
  43. {upd_cli-0.0.26 → upd_cli-0.0.27}/src/updater/csproj.rs +0 -0
  44. {upd_cli-0.0.26 → upd_cli-0.0.27}/src/updater/gemfile.rs +0 -0
  45. {upd_cli-0.0.26 → upd_cli-0.0.27}/src/updater/github_actions.rs +0 -0
  46. {upd_cli-0.0.26 → upd_cli-0.0.27}/src/updater/go_mod.rs +0 -0
  47. {upd_cli-0.0.26 → upd_cli-0.0.27}/src/updater/mise.rs +0 -0
  48. {upd_cli-0.0.26 → upd_cli-0.0.27}/src/updater/mod.rs +0 -0
  49. {upd_cli-0.0.26 → upd_cli-0.0.27}/src/updater/package_json.rs +0 -0
  50. {upd_cli-0.0.26 → upd_cli-0.0.27}/src/updater/pre_commit.rs +0 -0
  51. {upd_cli-0.0.26 → upd_cli-0.0.27}/src/updater/pyproject.rs +0 -0
  52. {upd_cli-0.0.26 → upd_cli-0.0.27}/src/updater/requirements.rs +0 -0
  53. {upd_cli-0.0.26 → upd_cli-0.0.27}/src/updater/terraform.rs +0 -0
  54. {upd_cli-0.0.26 → upd_cli-0.0.27}/src/version/semver_util.rs +0 -0
  55. {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
@@ -1780,7 +1780,7 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
1780
1780
 
1781
1781
  [[package]]
1782
1782
  name = "upd"
1783
- version = "0.0.26"
1783
+ version = "0.0.27"
1784
1784
  dependencies = [
1785
1785
  "anyhow",
1786
1786
  "async-trait",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "upd"
3
- version = "0.0.26"
3
+ version = "0.0.27"
4
4
  edition = "2024"
5
5
  rust-version = "1.91.1"
6
6
  description = "A fast dependency updater for Python, Node.js, Rust, Go, Ruby, Terraform, GitHub Actions, pre-commit, and Mise projects"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: upd-cli
3
- Version: 0.0.26
3
+ Version: 0.0.27
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Environment :: Console
6
6
  Classifier: Intended Audience :: Developers
@@ -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