upd-cli 0.0.23__tar.gz → 0.0.25__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.23 → upd_cli-0.0.25}/CHANGELOG.md +14 -0
- {upd_cli-0.0.23 → upd_cli-0.0.25}/Cargo.lock +1 -1
- {upd_cli-0.0.23 → upd_cli-0.0.25}/Cargo.toml +2 -2
- upd_cli-0.0.25/Makefile +57 -0
- {upd_cli-0.0.23 → upd_cli-0.0.25}/PKG-INFO +18 -11
- {upd_cli-0.0.23 → upd_cli-0.0.25}/README.md +15 -8
- {upd_cli-0.0.23 → upd_cli-0.0.25}/pyproject.toml +2 -2
- {upd_cli-0.0.23 → upd_cli-0.0.25}/src/align.rs +5 -4
- {upd_cli-0.0.23 → upd_cli-0.0.25}/src/cache.rs +6 -0
- {upd_cli-0.0.23 → upd_cli-0.0.25}/src/cli.rs +1 -1
- {upd_cli-0.0.23 → upd_cli-0.0.25}/src/lib.rs +1 -1
- {upd_cli-0.0.23 → upd_cli-0.0.25}/src/lockfile.rs +72 -0
- {upd_cli-0.0.23 → upd_cli-0.0.25}/src/main.rs +58 -5
- {upd_cli-0.0.23 → upd_cli-0.0.25}/src/registry/mod.rs +2 -0
- upd_cli-0.0.25/src/registry/nuget.rs +225 -0
- {upd_cli-0.0.23 → upd_cli-0.0.25}/src/registry/pypi.rs +147 -23
- upd_cli-0.0.25/src/updater/csproj.rs +666 -0
- {upd_cli-0.0.23 → upd_cli-0.0.25}/src/updater/mod.rs +22 -0
- upd_cli-0.0.25/vership.toml +2 -0
- upd_cli-0.0.23/Makefile +0 -127
- {upd_cli-0.0.23 → upd_cli-0.0.25}/.mise.toml +0 -0
- {upd_cli-0.0.23 → upd_cli-0.0.25}/.pre-commit-config.yaml +0 -0
- {upd_cli-0.0.23 → upd_cli-0.0.25}/.pre-commit-hooks.yaml +0 -0
- {upd_cli-0.0.23 → upd_cli-0.0.25}/.rumdl.toml +0 -0
- {upd_cli-0.0.23 → upd_cli-0.0.25}/LICENSE +0 -0
- {upd_cli-0.0.23 → upd_cli-0.0.25}/assets/logo-wide.svg +0 -0
- {upd_cli-0.0.23 → upd_cli-0.0.25}/assets/logo.svg +0 -0
- {upd_cli-0.0.23 → upd_cli-0.0.25}/python/upd_cli/__init__.py +0 -0
- {upd_cli-0.0.23 → upd_cli-0.0.25}/python/upd_cli/__main__.py +0 -0
- {upd_cli-0.0.23 → upd_cli-0.0.25}/python/upd_cli/py.typed +0 -0
- {upd_cli-0.0.23 → upd_cli-0.0.25}/rust-toolchain.toml +0 -0
- {upd_cli-0.0.23 → upd_cli-0.0.25}/src/audit.rs +0 -0
- {upd_cli-0.0.23 → upd_cli-0.0.25}/src/config.rs +0 -0
- {upd_cli-0.0.23 → upd_cli-0.0.25}/src/interactive.rs +0 -0
- {upd_cli-0.0.23 → upd_cli-0.0.25}/src/registry/crates_io.rs +0 -0
- {upd_cli-0.0.23 → upd_cli-0.0.25}/src/registry/github_releases.rs +0 -0
- {upd_cli-0.0.23 → upd_cli-0.0.25}/src/registry/go_proxy.rs +0 -0
- {upd_cli-0.0.23 → upd_cli-0.0.25}/src/registry/mock.rs +0 -0
- {upd_cli-0.0.23 → upd_cli-0.0.25}/src/registry/npm.rs +0 -0
- {upd_cli-0.0.23 → upd_cli-0.0.25}/src/registry/rubygems.rs +0 -0
- {upd_cli-0.0.23 → upd_cli-0.0.25}/src/registry/terraform.rs +0 -0
- {upd_cli-0.0.23 → upd_cli-0.0.25}/src/registry/utils.rs +0 -0
- {upd_cli-0.0.23 → upd_cli-0.0.25}/src/updater/cargo_toml.rs +0 -0
- {upd_cli-0.0.23 → upd_cli-0.0.25}/src/updater/gemfile.rs +0 -0
- {upd_cli-0.0.23 → upd_cli-0.0.25}/src/updater/github_actions.rs +0 -0
- {upd_cli-0.0.23 → upd_cli-0.0.25}/src/updater/go_mod.rs +0 -0
- {upd_cli-0.0.23 → upd_cli-0.0.25}/src/updater/mise.rs +0 -0
- {upd_cli-0.0.23 → upd_cli-0.0.25}/src/updater/package_json.rs +0 -0
- {upd_cli-0.0.23 → upd_cli-0.0.25}/src/updater/pre_commit.rs +0 -0
- {upd_cli-0.0.23 → upd_cli-0.0.25}/src/updater/pyproject.rs +0 -0
- {upd_cli-0.0.23 → upd_cli-0.0.25}/src/updater/requirements.rs +0 -0
- {upd_cli-0.0.23 → upd_cli-0.0.25}/src/updater/terraform.rs +0 -0
- {upd_cli-0.0.23 → upd_cli-0.0.25}/src/version/mod.rs +0 -0
- {upd_cli-0.0.23 → upd_cli-0.0.25}/src/version/pep440.rs +0 -0
- {upd_cli-0.0.23 → upd_cli-0.0.25}/src/version/semver_util.rs +0 -0
|
@@ -5,6 +5,20 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
|
|
9
|
+
## [0.0.25](https://github.com/rvben/upd/compare/v0.0.24...v0.0.25) - 2026-04-15
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- **pypi**: handle string-valued yanked field in PEP 691 JSON Simple API ([b17034b](https://github.com/rvben/upd/commit/b17034b540f6a5b62e446131c6e87f43695bbd9b))
|
|
14
|
+
|
|
15
|
+
## [0.0.24] - 2026-03-23
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
- **NuGet/.NET support**: Update `PackageReference` and `PackageVersion` elements in `.csproj` and `Directory.Packages.props` files via the NuGet v3 API
|
|
20
|
+
- **Gemfile.lock regeneration**: `--lock` flag now supports Ruby projects (runs `bundle install`)
|
|
21
|
+
|
|
8
22
|
## [0.0.23] - 2026-03-23
|
|
9
23
|
|
|
10
24
|
### Added
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "upd"
|
|
3
|
-
version = "0.0.
|
|
3
|
+
version = "0.0.25"
|
|
4
4
|
edition = "2024"
|
|
5
5
|
rust-version = "1.91.1"
|
|
6
|
-
description = "A fast dependency updater for Python, Node.js, Rust, Go,
|
|
6
|
+
description = "A fast dependency updater for Python, Node.js, Rust, Go, Ruby, Terraform, GitHub Actions, pre-commit, and Mise projects"
|
|
7
7
|
license = "MIT"
|
|
8
8
|
repository = "https://github.com/rvben/upd"
|
|
9
9
|
homepage = "https://github.com/rvben/upd"
|
upd_cli-0.0.25/Makefile
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
.PHONY: build release test lint fmt check clean run install release-patch release-minor release-major
|
|
2
|
+
|
|
3
|
+
# Build debug binary
|
|
4
|
+
build:
|
|
5
|
+
cargo build
|
|
6
|
+
|
|
7
|
+
# Build release binary
|
|
8
|
+
release:
|
|
9
|
+
cargo build --release
|
|
10
|
+
|
|
11
|
+
# Run all tests
|
|
12
|
+
test:
|
|
13
|
+
cargo test
|
|
14
|
+
|
|
15
|
+
# Run tests with output
|
|
16
|
+
test-verbose:
|
|
17
|
+
cargo test -- --nocapture
|
|
18
|
+
|
|
19
|
+
# Run clippy lints
|
|
20
|
+
lint:
|
|
21
|
+
cargo clippy -- -D warnings
|
|
22
|
+
|
|
23
|
+
# Format code
|
|
24
|
+
fmt:
|
|
25
|
+
cargo fmt
|
|
26
|
+
|
|
27
|
+
# Check formatting without changing files
|
|
28
|
+
fmt-check:
|
|
29
|
+
cargo fmt -- --check
|
|
30
|
+
|
|
31
|
+
# Run all checks (format, lint, test)
|
|
32
|
+
check: fmt-check lint test
|
|
33
|
+
|
|
34
|
+
# Clean build artifacts
|
|
35
|
+
clean:
|
|
36
|
+
cargo clean
|
|
37
|
+
|
|
38
|
+
# Run debug build
|
|
39
|
+
run:
|
|
40
|
+
cargo run
|
|
41
|
+
|
|
42
|
+
# Run with arguments
|
|
43
|
+
run-release:
|
|
44
|
+
./target/release/upd
|
|
45
|
+
|
|
46
|
+
# Install to ~/.cargo/bin
|
|
47
|
+
install:
|
|
48
|
+
cargo install --path .
|
|
49
|
+
|
|
50
|
+
release-patch:
|
|
51
|
+
vership bump patch
|
|
52
|
+
|
|
53
|
+
release-minor:
|
|
54
|
+
vership bump minor
|
|
55
|
+
|
|
56
|
+
release-major:
|
|
57
|
+
vership bump major
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: upd-cli
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.25
|
|
4
4
|
Classifier: Development Status :: 4 - Beta
|
|
5
5
|
Classifier: Environment :: Console
|
|
6
6
|
Classifier: Intended Audience :: Developers
|
|
@@ -10,8 +10,8 @@ Classifier: Programming Language :: Python :: 3
|
|
|
10
10
|
Classifier: Programming Language :: Rust
|
|
11
11
|
Classifier: Topic :: Software Development :: Build Tools
|
|
12
12
|
License-File: LICENSE
|
|
13
|
-
Summary: A fast dependency updater for Python
|
|
14
|
-
Keywords: dependencies,update,python,nodejs,
|
|
13
|
+
Summary: A fast dependency updater for Python, Node.js, Rust, Go, Ruby, Terraform, GitHub Actions, pre-commit, and Mise projects
|
|
14
|
+
Keywords: dependencies,update,python,nodejs,rust,go,ruby,terraform,github-actions
|
|
15
15
|
Home-Page: https://github.com/rvben/upd
|
|
16
16
|
Author-email: Ruben Jongejan <ruben.jongejan@gmail.com>
|
|
17
17
|
License: MIT
|
|
@@ -27,7 +27,7 @@ Project-URL: Repository, https://github.com/rvben/upd
|
|
|
27
27
|
|
|
28
28
|
# upd
|
|
29
29
|
|
|
30
|
-
A fast dependency updater for Python, Node.js, Rust, Go, Ruby, Terraform, GitHub Actions, pre-commit, and Mise projects, written in Rust.
|
|
30
|
+
A fast dependency updater for Python, Node.js, Rust, Go, Ruby, .NET, Terraform, GitHub Actions, pre-commit, and Mise projects, written in Rust.
|
|
31
31
|
|
|
32
32
|
## Quick Start
|
|
33
33
|
|
|
@@ -44,7 +44,7 @@ uvx --from upd-cli upd -n
|
|
|
44
44
|
|
|
45
45
|
## Features
|
|
46
46
|
|
|
47
|
-
- **Multi-ecosystem**: Python, Node.js, Rust, Go, Ruby, Terraform, GitHub Actions, pre-commit, Mise/asdf
|
|
47
|
+
- **Multi-ecosystem**: Python, Node.js, Rust, Go, Ruby, .NET, Terraform, GitHub Actions, pre-commit, Mise/asdf
|
|
48
48
|
- **Fast**: Parallel registry requests for all dependencies
|
|
49
49
|
- **Constraint-aware**: Respects version constraints like `>=2.0,<3` and `~> 7.1`
|
|
50
50
|
- **Smart caching**: 24-hour version cache for faster subsequent runs
|
|
@@ -129,6 +129,7 @@ upd --lang python --lang go # Update Python and Go only
|
|
|
129
129
|
upd --lang actions # Update only GitHub Actions
|
|
130
130
|
upd --lang pre-commit # Update only pre-commit hooks
|
|
131
131
|
upd --lang ruby # Update only Ruby gems
|
|
132
|
+
upd --lang dot-net # Update only .NET NuGet packages
|
|
132
133
|
upd --lang terraform # Update only Terraform providers/modules
|
|
133
134
|
upd --lang mise # Update only Mise/asdf tools
|
|
134
135
|
|
|
@@ -191,6 +192,14 @@ upd audit --check # Exit 1 if vulnerabilities found (for CI)
|
|
|
191
192
|
|
|
192
193
|
- `Gemfile` (gem declarations with version constraints)
|
|
193
194
|
|
|
195
|
+
### .NET / NuGet
|
|
196
|
+
|
|
197
|
+
- `.csproj` files (`PackageReference` elements)
|
|
198
|
+
- `Directory.Packages.props` and `Directory.Build.props` (`PackageVersion` elements)
|
|
199
|
+
- Supports both inline `Version` attributes and child `<Version>` elements
|
|
200
|
+
- Queries the NuGet v3 API (`api.nuget.org`)
|
|
201
|
+
- Skips range version constraints (`[1.0, 2.0)`)
|
|
202
|
+
|
|
194
203
|
### Terraform / OpenTofu
|
|
195
204
|
|
|
196
205
|
- `.tf` files (HCL format)
|
|
@@ -324,7 +333,7 @@ Checking 42 unique package(s) for vulnerabilities...
|
|
|
324
333
|
Summary: 2 vulnerable package(s), 3 total vulnerability/ies
|
|
325
334
|
```
|
|
326
335
|
|
|
327
|
-
**Supported ecosystems for auditing:** PyPI, npm, crates.io, Go, RubyGems
|
|
336
|
+
**Supported ecosystems for auditing:** PyPI, npm, crates.io, Go, RubyGems, NuGet
|
|
328
337
|
|
|
329
338
|
**CI/CD Integration:**
|
|
330
339
|
|
|
@@ -586,8 +595,8 @@ Add `upd` to your `.pre-commit-config.yaml`:
|
|
|
586
595
|
|
|
587
596
|
```yaml
|
|
588
597
|
repos:
|
|
589
|
-
- repo: https://github.com/rvben/upd
|
|
590
|
-
rev: v0.0.
|
|
598
|
+
- repo: https://github.com/rvben/upd-pre-commit
|
|
599
|
+
rev: v0.0.24
|
|
591
600
|
hooks:
|
|
592
601
|
- id: upd-check
|
|
593
602
|
# Optional: only check specific ecosystems
|
|
@@ -601,9 +610,7 @@ Available hooks:
|
|
|
601
610
|
| `upd-check` | Fail if any dependencies are outdated |
|
|
602
611
|
| `upd-check-major` | Fail only on major (breaking) updates |
|
|
603
612
|
|
|
604
|
-
Both hooks run on `pre-push` by default
|
|
605
|
-
|
|
606
|
-
**Note:** Requires `upd` to be installed and available in PATH.
|
|
613
|
+
Both hooks run on `pre-push` by default. Uses `language: python` which installs `upd-cli` from PyPI automatically — no manual installation needed.
|
|
607
614
|
|
|
608
615
|
## Development
|
|
609
616
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
# upd
|
|
6
6
|
|
|
7
|
-
A fast dependency updater for Python, Node.js, Rust, Go, Ruby, Terraform, GitHub Actions, pre-commit, and Mise projects, written in Rust.
|
|
7
|
+
A fast dependency updater for Python, Node.js, Rust, Go, Ruby, .NET, Terraform, GitHub Actions, pre-commit, and Mise projects, written in Rust.
|
|
8
8
|
|
|
9
9
|
## Quick Start
|
|
10
10
|
|
|
@@ -21,7 +21,7 @@ uvx --from upd-cli upd -n
|
|
|
21
21
|
|
|
22
22
|
## Features
|
|
23
23
|
|
|
24
|
-
- **Multi-ecosystem**: Python, Node.js, Rust, Go, Ruby, Terraform, GitHub Actions, pre-commit, Mise/asdf
|
|
24
|
+
- **Multi-ecosystem**: Python, Node.js, Rust, Go, Ruby, .NET, Terraform, GitHub Actions, pre-commit, Mise/asdf
|
|
25
25
|
- **Fast**: Parallel registry requests for all dependencies
|
|
26
26
|
- **Constraint-aware**: Respects version constraints like `>=2.0,<3` and `~> 7.1`
|
|
27
27
|
- **Smart caching**: 24-hour version cache for faster subsequent runs
|
|
@@ -106,6 +106,7 @@ upd --lang python --lang go # Update Python and Go only
|
|
|
106
106
|
upd --lang actions # Update only GitHub Actions
|
|
107
107
|
upd --lang pre-commit # Update only pre-commit hooks
|
|
108
108
|
upd --lang ruby # Update only Ruby gems
|
|
109
|
+
upd --lang dot-net # Update only .NET NuGet packages
|
|
109
110
|
upd --lang terraform # Update only Terraform providers/modules
|
|
110
111
|
upd --lang mise # Update only Mise/asdf tools
|
|
111
112
|
|
|
@@ -168,6 +169,14 @@ upd audit --check # Exit 1 if vulnerabilities found (for CI)
|
|
|
168
169
|
|
|
169
170
|
- `Gemfile` (gem declarations with version constraints)
|
|
170
171
|
|
|
172
|
+
### .NET / NuGet
|
|
173
|
+
|
|
174
|
+
- `.csproj` files (`PackageReference` elements)
|
|
175
|
+
- `Directory.Packages.props` and `Directory.Build.props` (`PackageVersion` elements)
|
|
176
|
+
- Supports both inline `Version` attributes and child `<Version>` elements
|
|
177
|
+
- Queries the NuGet v3 API (`api.nuget.org`)
|
|
178
|
+
- Skips range version constraints (`[1.0, 2.0)`)
|
|
179
|
+
|
|
171
180
|
### Terraform / OpenTofu
|
|
172
181
|
|
|
173
182
|
- `.tf` files (HCL format)
|
|
@@ -301,7 +310,7 @@ Checking 42 unique package(s) for vulnerabilities...
|
|
|
301
310
|
Summary: 2 vulnerable package(s), 3 total vulnerability/ies
|
|
302
311
|
```
|
|
303
312
|
|
|
304
|
-
**Supported ecosystems for auditing:** PyPI, npm, crates.io, Go, RubyGems
|
|
313
|
+
**Supported ecosystems for auditing:** PyPI, npm, crates.io, Go, RubyGems, NuGet
|
|
305
314
|
|
|
306
315
|
**CI/CD Integration:**
|
|
307
316
|
|
|
@@ -563,8 +572,8 @@ Add `upd` to your `.pre-commit-config.yaml`:
|
|
|
563
572
|
|
|
564
573
|
```yaml
|
|
565
574
|
repos:
|
|
566
|
-
- repo: https://github.com/rvben/upd
|
|
567
|
-
rev: v0.0.
|
|
575
|
+
- repo: https://github.com/rvben/upd-pre-commit
|
|
576
|
+
rev: v0.0.24
|
|
568
577
|
hooks:
|
|
569
578
|
- id: upd-check
|
|
570
579
|
# Optional: only check specific ecosystems
|
|
@@ -578,9 +587,7 @@ Available hooks:
|
|
|
578
587
|
| `upd-check` | Fail if any dependencies are outdated |
|
|
579
588
|
| `upd-check-major` | Fail only on major (breaking) updates |
|
|
580
589
|
|
|
581
|
-
Both hooks run on `pre-push` by default
|
|
582
|
-
|
|
583
|
-
**Note:** Requires `upd` to be installed and available in PATH.
|
|
590
|
+
Both hooks run on `pre-push` by default. Uses `language: python` which installs `upd-cli` from PyPI automatically — no manual installation needed.
|
|
584
591
|
|
|
585
592
|
## Development
|
|
586
593
|
|
|
@@ -5,11 +5,11 @@ build-backend = "maturin"
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "upd-cli"
|
|
7
7
|
dynamic = ["version"]
|
|
8
|
-
description = "A fast dependency updater for Python
|
|
8
|
+
description = "A fast dependency updater for Python, Node.js, Rust, Go, Ruby, Terraform, GitHub Actions, pre-commit, and Mise projects"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
11
11
|
authors = [{ name = "Ruben Jongejan", email = "ruben.jongejan@gmail.com" }]
|
|
12
|
-
keywords = ["dependencies", "update", "python", "nodejs", "
|
|
12
|
+
keywords = ["dependencies", "update", "python", "nodejs", "rust", "go", "ruby", "terraform", "github-actions"]
|
|
13
13
|
classifiers = [
|
|
14
14
|
"Development Status :: 4 - Beta",
|
|
15
15
|
"Environment :: Console",
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
//! used across multiple dependency files and update all occurrences to that version.
|
|
5
5
|
|
|
6
6
|
use crate::updater::{
|
|
7
|
-
CargoTomlUpdater, FileType, GemfileUpdater, GithubActionsUpdater, GoModUpdater,
|
|
8
|
-
MiseUpdater, PackageJsonUpdater, ParsedDependency, PreCommitUpdater, PyProjectUpdater,
|
|
7
|
+
CargoTomlUpdater, CsprojUpdater, FileType, GemfileUpdater, GithubActionsUpdater, GoModUpdater,
|
|
8
|
+
Lang, MiseUpdater, PackageJsonUpdater, ParsedDependency, PreCommitUpdater, PyProjectUpdater,
|
|
9
9
|
RequirementsUpdater, TerraformUpdater, Updater,
|
|
10
10
|
};
|
|
11
11
|
use anyhow::Result;
|
|
@@ -78,6 +78,7 @@ fn get_updater(file_type: FileType) -> Box<dyn Updater> {
|
|
|
78
78
|
FileType::CargoToml => Box::new(CargoTomlUpdater::new()),
|
|
79
79
|
FileType::GoMod => Box::new(GoModUpdater::new()),
|
|
80
80
|
FileType::Gemfile => Box::new(GemfileUpdater::new()),
|
|
81
|
+
FileType::Csproj => Box::new(CsprojUpdater::new()),
|
|
81
82
|
FileType::GithubActions => Box::new(GithubActionsUpdater::new()),
|
|
82
83
|
FileType::PreCommitConfig => Box::new(PreCommitUpdater::new()),
|
|
83
84
|
FileType::MiseToml | FileType::ToolVersions => Box::new(MiseUpdater::new()),
|
|
@@ -179,7 +180,7 @@ fn is_stable_version(version: &str, lang: Lang) -> bool {
|
|
|
179
180
|
&& !v.contains("beta")
|
|
180
181
|
&& !v.contains("dev")
|
|
181
182
|
}
|
|
182
|
-
Lang::Node | Lang::Rust | Lang::Go => {
|
|
183
|
+
Lang::Node | Lang::Rust | Lang::Go | Lang::DotNet => {
|
|
183
184
|
// Semver pre-release indicator: hyphen followed by identifier
|
|
184
185
|
!version.contains('-')
|
|
185
186
|
}
|
|
@@ -201,7 +202,7 @@ fn is_stable_version(version: &str, lang: Lang) -> bool {
|
|
|
201
202
|
fn compare_versions(a: &str, b: &str, lang: Lang) -> std::cmp::Ordering {
|
|
202
203
|
match lang {
|
|
203
204
|
Lang::Python => compare_pep440(a, b),
|
|
204
|
-
Lang::Node | Lang::Rust | Lang::Ruby => compare_semver(a, b),
|
|
205
|
+
Lang::Node | Lang::Rust | Lang::Ruby | Lang::DotNet => compare_semver(a, b),
|
|
205
206
|
Lang::Go => compare_go_version(a, b),
|
|
206
207
|
Lang::Actions | Lang::PreCommit | Lang::Mise | Lang::Terraform => {
|
|
207
208
|
let clean_a = a.trim_start_matches('v');
|
|
@@ -27,6 +27,8 @@ pub struct Cache {
|
|
|
27
27
|
rubygems: HashMap<String, CacheEntry>,
|
|
28
28
|
#[serde(default)]
|
|
29
29
|
terraform: HashMap<String, CacheEntry>,
|
|
30
|
+
#[serde(default)]
|
|
31
|
+
nuget: HashMap<String, CacheEntry>,
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
@@ -83,6 +85,7 @@ impl Cache {
|
|
|
83
85
|
"github-releases" => &self.github_releases,
|
|
84
86
|
"rubygems" => &self.rubygems,
|
|
85
87
|
"terraform" => &self.terraform,
|
|
88
|
+
"nuget" => &self.nuget,
|
|
86
89
|
_ => return None,
|
|
87
90
|
};
|
|
88
91
|
|
|
@@ -104,6 +107,7 @@ impl Cache {
|
|
|
104
107
|
"github-releases" => &mut self.github_releases,
|
|
105
108
|
"rubygems" => &mut self.rubygems,
|
|
106
109
|
"terraform" => &mut self.terraform,
|
|
110
|
+
"nuget" => &mut self.nuget,
|
|
107
111
|
_ => return,
|
|
108
112
|
};
|
|
109
113
|
|
|
@@ -167,6 +171,8 @@ impl Cache {
|
|
|
167
171
|
.retain(|_, entry| !Self::is_expired(entry.fetched_at));
|
|
168
172
|
self.terraform
|
|
169
173
|
.retain(|_, entry| !Self::is_expired(entry.fetched_at));
|
|
174
|
+
self.nuget
|
|
175
|
+
.retain(|_, entry| !Self::is_expired(entry.fetched_at));
|
|
170
176
|
}
|
|
171
177
|
}
|
|
172
178
|
|
|
@@ -7,7 +7,7 @@ use std::path::PathBuf;
|
|
|
7
7
|
#[command(
|
|
8
8
|
author,
|
|
9
9
|
version,
|
|
10
|
-
about = "A fast dependency updater for Python, Node.js, Rust, Go, Ruby, Terraform, GitHub Actions, pre-commit, and Mise/asdf projects"
|
|
10
|
+
about = "A fast dependency updater for Python, Node.js, Rust, Go, Ruby, .NET, Terraform, GitHub Actions, pre-commit, and Mise/asdf projects"
|
|
11
11
|
)]
|
|
12
12
|
pub struct Cli {
|
|
13
13
|
#[command(subcommand)]
|
|
@@ -16,7 +16,7 @@ pub use cli::{Cli, Command};
|
|
|
16
16
|
pub use config::UpdConfig;
|
|
17
17
|
pub use lockfile::{LockfileType, detect_lockfiles, regenerate_lockfiles};
|
|
18
18
|
pub use registry::{
|
|
19
|
-
GitHubReleasesRegistry, NpmRegistry, PyPiRegistry, Registry, RubyGemsRegistry,
|
|
19
|
+
GitHubReleasesRegistry, NpmRegistry, NuGetRegistry, PyPiRegistry, Registry, RubyGemsRegistry,
|
|
20
20
|
TerraformRegistry,
|
|
21
21
|
};
|
|
22
22
|
pub use updater::{FileType, Lang, UpdateResult, Updater, discover_files};
|
|
@@ -27,6 +27,8 @@ pub enum LockfileType {
|
|
|
27
27
|
CargoLock,
|
|
28
28
|
/// go.sum - regenerated with `go mod tidy`
|
|
29
29
|
GoSum,
|
|
30
|
+
/// Gemfile.lock - regenerated with `bundle install`
|
|
31
|
+
GemfileLock,
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
impl LockfileType {
|
|
@@ -41,6 +43,7 @@ impl LockfileType {
|
|
|
41
43
|
LockfileType::BunLock => "bun.lockb",
|
|
42
44
|
LockfileType::CargoLock => "Cargo.lock",
|
|
43
45
|
LockfileType::GoSum => "go.sum",
|
|
46
|
+
LockfileType::GemfileLock => "Gemfile.lock",
|
|
44
47
|
}
|
|
45
48
|
}
|
|
46
49
|
|
|
@@ -55,6 +58,7 @@ impl LockfileType {
|
|
|
55
58
|
LockfileType::BunLock => ("bun", &["install"]),
|
|
56
59
|
LockfileType::CargoLock => ("cargo", &["update"]),
|
|
57
60
|
LockfileType::GoSum => ("go", &["mod", "tidy"]),
|
|
61
|
+
LockfileType::GemfileLock => ("bundle", &["install"]),
|
|
58
62
|
}
|
|
59
63
|
}
|
|
60
64
|
|
|
@@ -68,6 +72,7 @@ impl LockfileType {
|
|
|
68
72
|
| LockfileType::BunLock => "package.json",
|
|
69
73
|
LockfileType::CargoLock => "Cargo.toml",
|
|
70
74
|
LockfileType::GoSum => "go.mod",
|
|
75
|
+
LockfileType::GemfileLock => "Gemfile",
|
|
71
76
|
}
|
|
72
77
|
}
|
|
73
78
|
}
|
|
@@ -131,6 +136,16 @@ pub fn detect_lockfiles(manifest_path: &Path) -> Vec<LockfileType> {
|
|
|
131
136
|
lockfiles.push(LockfileType::GoSum);
|
|
132
137
|
}
|
|
133
138
|
|
|
139
|
+
// Check for Ruby lockfile (only if manifest is Gemfile)
|
|
140
|
+
if manifest_path
|
|
141
|
+
.file_name()
|
|
142
|
+
.map(|n| n == "Gemfile")
|
|
143
|
+
.unwrap_or(false)
|
|
144
|
+
&& dir.join("Gemfile.lock").exists()
|
|
145
|
+
{
|
|
146
|
+
lockfiles.push(LockfileType::GemfileLock);
|
|
147
|
+
}
|
|
148
|
+
|
|
134
149
|
lockfiles
|
|
135
150
|
}
|
|
136
151
|
|
|
@@ -407,4 +422,61 @@ mod tests {
|
|
|
407
422
|
let detected = detect_lockfiles(&manifest);
|
|
408
423
|
assert!(detected.is_empty());
|
|
409
424
|
}
|
|
425
|
+
|
|
426
|
+
#[test]
|
|
427
|
+
fn test_lockfile_type_gemfile_filename() {
|
|
428
|
+
assert_eq!(LockfileType::GemfileLock.filename(), "Gemfile.lock");
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
#[test]
|
|
432
|
+
fn test_lockfile_type_gemfile_command() {
|
|
433
|
+
let (cmd, args) = LockfileType::GemfileLock.command();
|
|
434
|
+
assert_eq!(cmd, "bundle");
|
|
435
|
+
assert_eq!(args, &["install"]);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
#[test]
|
|
439
|
+
fn test_lockfile_type_gemfile_manifest() {
|
|
440
|
+
assert_eq!(LockfileType::GemfileLock.manifest(), "Gemfile");
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
#[test]
|
|
444
|
+
fn test_detect_lockfiles_gemfile() {
|
|
445
|
+
let dir = tempdir().unwrap();
|
|
446
|
+
let manifest = dir.path().join("Gemfile");
|
|
447
|
+
let lockfile = dir.path().join("Gemfile.lock");
|
|
448
|
+
|
|
449
|
+
fs::write(&manifest, "source 'https://rubygems.org'").unwrap();
|
|
450
|
+
fs::write(&lockfile, "").unwrap();
|
|
451
|
+
|
|
452
|
+
let detected = detect_lockfiles(&manifest);
|
|
453
|
+
assert_eq!(detected.len(), 1);
|
|
454
|
+
assert_eq!(detected[0], LockfileType::GemfileLock);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
#[test]
|
|
458
|
+
fn test_detect_lockfiles_gemfile_no_lockfile() {
|
|
459
|
+
// Gemfile without Gemfile.lock should not detect any lockfile
|
|
460
|
+
let dir = tempdir().unwrap();
|
|
461
|
+
let manifest = dir.path().join("Gemfile");
|
|
462
|
+
|
|
463
|
+
fs::write(&manifest, "source 'https://rubygems.org'").unwrap();
|
|
464
|
+
|
|
465
|
+
let detected = detect_lockfiles(&manifest);
|
|
466
|
+
assert!(detected.is_empty());
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
#[test]
|
|
470
|
+
fn test_detect_lockfiles_gemfile_wrong_manifest() {
|
|
471
|
+
// Gemfile.lock should only be detected for Gemfile, not for other manifests
|
|
472
|
+
let dir = tempdir().unwrap();
|
|
473
|
+
let manifest = dir.path().join("pyproject.toml");
|
|
474
|
+
let lockfile = dir.path().join("Gemfile.lock");
|
|
475
|
+
|
|
476
|
+
fs::write(&manifest, "[project]").unwrap();
|
|
477
|
+
fs::write(&lockfile, "").unwrap();
|
|
478
|
+
|
|
479
|
+
let detected = detect_lockfiles(&manifest);
|
|
480
|
+
assert!(detected.is_empty());
|
|
481
|
+
}
|
|
410
482
|
}
|
|
@@ -15,11 +15,11 @@ use upd::interactive::{PendingUpdate, prompt_all};
|
|
|
15
15
|
use upd::lockfile::regenerate_lockfiles;
|
|
16
16
|
use upd::registry::{
|
|
17
17
|
CratesIoRegistry, GitHubReleasesRegistry, GoProxyRegistry, MultiPyPiRegistry, NpmRegistry,
|
|
18
|
-
PyPiRegistry, RubyGemsRegistry, TerraformRegistry,
|
|
18
|
+
NuGetRegistry, PyPiRegistry, RubyGemsRegistry, TerraformRegistry,
|
|
19
19
|
};
|
|
20
20
|
use upd::updater::{
|
|
21
|
-
CargoTomlUpdater, FileType, GemfileUpdater, GithubActionsUpdater, GoModUpdater,
|
|
22
|
-
MiseUpdater, PackageJsonUpdater, PreCommitUpdater, PyProjectUpdater, RequirementsUpdater,
|
|
21
|
+
CargoTomlUpdater, CsprojUpdater, FileType, GemfileUpdater, GithubActionsUpdater, GoModUpdater,
|
|
22
|
+
Lang, MiseUpdater, PackageJsonUpdater, PreCommitUpdater, PyProjectUpdater, RequirementsUpdater,
|
|
23
23
|
TerraformUpdater, UpdateOptions, UpdateResult, Updater, discover_files, read_file_safe,
|
|
24
24
|
write_file_atomic,
|
|
25
25
|
};
|
|
@@ -245,6 +245,10 @@ async fn run_update(cli: &Cli) -> Result<()> {
|
|
|
245
245
|
let terraform_registry = TerraformRegistry::new();
|
|
246
246
|
let terraform = CachedRegistry::new(terraform_registry, Arc::clone(&cache), cache_enabled);
|
|
247
247
|
|
|
248
|
+
// Create NuGet registry
|
|
249
|
+
let nuget_registry = NuGetRegistry::new();
|
|
250
|
+
let nuget = CachedRegistry::new(nuget_registry, Arc::clone(&cache), cache_enabled);
|
|
251
|
+
|
|
248
252
|
// Create GitHub releases registry with optional token
|
|
249
253
|
let github_releases_registry = GitHubReleasesRegistry::new();
|
|
250
254
|
if cli.verbose && GitHubReleasesRegistry::detect_token().is_some() {
|
|
@@ -264,6 +268,7 @@ async fn run_update(cli: &Cli) -> Result<()> {
|
|
|
264
268
|
let gemfile_updater = Arc::new(GemfileUpdater::new());
|
|
265
269
|
let mise_updater = Arc::new(MiseUpdater::new());
|
|
266
270
|
let terraform_updater = Arc::new(TerraformUpdater::new());
|
|
271
|
+
let csproj_updater = Arc::new(CsprojUpdater::new());
|
|
267
272
|
|
|
268
273
|
// Wrap registries in Arc for parallel processing
|
|
269
274
|
let pypi = Arc::new(pypi);
|
|
@@ -272,6 +277,7 @@ async fn run_update(cli: &Cli) -> Result<()> {
|
|
|
272
277
|
let go_proxy = Arc::new(go_proxy);
|
|
273
278
|
let rubygems = Arc::new(rubygems);
|
|
274
279
|
let terraform = Arc::new(terraform);
|
|
280
|
+
let nuget = Arc::new(nuget);
|
|
275
281
|
let github_releases = Arc::new(github_releases);
|
|
276
282
|
|
|
277
283
|
// Interactive mode: first discover updates, then prompt, then apply approved ones
|
|
@@ -287,6 +293,7 @@ async fn run_update(cli: &Cli) -> Result<()> {
|
|
|
287
293
|
&go_proxy,
|
|
288
294
|
&rubygems,
|
|
289
295
|
&terraform,
|
|
296
|
+
&nuget,
|
|
290
297
|
&github_releases,
|
|
291
298
|
&requirements_updater,
|
|
292
299
|
&pyproject_updater,
|
|
@@ -298,6 +305,7 @@ async fn run_update(cli: &Cli) -> Result<()> {
|
|
|
298
305
|
&pre_commit_updater,
|
|
299
306
|
&mise_updater,
|
|
300
307
|
&terraform_updater,
|
|
308
|
+
&csproj_updater,
|
|
301
309
|
&cache,
|
|
302
310
|
cache_enabled,
|
|
303
311
|
)
|
|
@@ -328,6 +336,7 @@ async fn run_update(cli: &Cli) -> Result<()> {
|
|
|
328
336
|
let go_proxy = Arc::clone(&go_proxy);
|
|
329
337
|
let rubygems = Arc::clone(&rubygems);
|
|
330
338
|
let terraform = Arc::clone(&terraform);
|
|
339
|
+
let nuget = Arc::clone(&nuget);
|
|
331
340
|
let github_releases = Arc::clone(&github_releases);
|
|
332
341
|
let requirements_updater = Arc::clone(&requirements_updater);
|
|
333
342
|
let pyproject_updater = Arc::clone(&pyproject_updater);
|
|
@@ -338,6 +347,7 @@ async fn run_update(cli: &Cli) -> Result<()> {
|
|
|
338
347
|
let github_actions_updater = Arc::clone(&github_actions_updater);
|
|
339
348
|
let pre_commit_updater = Arc::clone(&pre_commit_updater);
|
|
340
349
|
let mise_updater = Arc::clone(&mise_updater);
|
|
350
|
+
let csproj_updater = Arc::clone(&csproj_updater);
|
|
341
351
|
let terraform_updater = Arc::clone(&terraform_updater);
|
|
342
352
|
let update_options = update_options.clone();
|
|
343
353
|
|
|
@@ -388,6 +398,11 @@ async fn run_update(cli: &Cli) -> Result<()> {
|
|
|
388
398
|
.update(&path, github_releases.as_ref(), update_options.clone())
|
|
389
399
|
.await
|
|
390
400
|
}
|
|
401
|
+
FileType::Csproj => {
|
|
402
|
+
csproj_updater
|
|
403
|
+
.update(&path, nuget.as_ref(), update_options.clone())
|
|
404
|
+
.await
|
|
405
|
+
}
|
|
391
406
|
FileType::TerraformTf => {
|
|
392
407
|
terraform_updater
|
|
393
408
|
.update(&path, terraform.as_ref(), update_options.clone())
|
|
@@ -489,6 +504,7 @@ async fn run_interactive_update(
|
|
|
489
504
|
go_proxy: &Arc<CachedRegistry<GoProxyRegistry>>,
|
|
490
505
|
rubygems: &Arc<CachedRegistry<RubyGemsRegistry>>,
|
|
491
506
|
terraform: &Arc<CachedRegistry<TerraformRegistry>>,
|
|
507
|
+
nuget: &Arc<CachedRegistry<NuGetRegistry>>,
|
|
492
508
|
github_releases: &Arc<CachedRegistry<GitHubReleasesRegistry>>,
|
|
493
509
|
requirements_updater: &Arc<RequirementsUpdater>,
|
|
494
510
|
pyproject_updater: &Arc<PyProjectUpdater>,
|
|
@@ -500,6 +516,7 @@ async fn run_interactive_update(
|
|
|
500
516
|
pre_commit_updater: &Arc<PreCommitUpdater>,
|
|
501
517
|
mise_updater: &Arc<MiseUpdater>,
|
|
502
518
|
terraform_updater: &Arc<TerraformUpdater>,
|
|
519
|
+
csproj_updater: &Arc<CsprojUpdater>,
|
|
503
520
|
cache: &Arc<std::sync::Mutex<Cache>>,
|
|
504
521
|
cache_enabled: bool,
|
|
505
522
|
) -> Result<()> {
|
|
@@ -565,6 +582,11 @@ async fn run_interactive_update(
|
|
|
565
582
|
.update(path, github_releases.as_ref(), dry_run_options.clone())
|
|
566
583
|
.await
|
|
567
584
|
}
|
|
585
|
+
FileType::Csproj => {
|
|
586
|
+
csproj_updater
|
|
587
|
+
.update(path, nuget.as_ref(), dry_run_options.clone())
|
|
588
|
+
.await
|
|
589
|
+
}
|
|
568
590
|
FileType::TerraformTf => {
|
|
569
591
|
terraform_updater
|
|
570
592
|
.update(path, terraform.as_ref(), dry_run_options.clone())
|
|
@@ -690,6 +712,11 @@ async fn run_interactive_update(
|
|
|
690
712
|
.update(path, github_releases.as_ref(), apply_options.clone())
|
|
691
713
|
.await
|
|
692
714
|
}
|
|
715
|
+
FileType::Csproj => {
|
|
716
|
+
csproj_updater
|
|
717
|
+
.update(path, nuget.as_ref(), apply_options.clone())
|
|
718
|
+
.await
|
|
719
|
+
}
|
|
693
720
|
FileType::TerraformTf => {
|
|
694
721
|
terraform_updater
|
|
695
722
|
.update(path, terraform.as_ref(), apply_options.clone())
|
|
@@ -884,11 +911,12 @@ async fn run_audit(cli: &Cli) -> Result<()> {
|
|
|
884
911
|
std::collections::HashSet::new();
|
|
885
912
|
|
|
886
913
|
for ((name, lang), occurrences) in &packages {
|
|
887
|
-
// OSV doesn't cover GitHub Actions, pre-commit hooks, mise tools, or
|
|
914
|
+
// OSV doesn't cover GitHub Actions, pre-commit hooks, mise tools, Terraform, or .NET; skip
|
|
888
915
|
if *lang == Lang::Actions
|
|
889
916
|
|| *lang == Lang::PreCommit
|
|
890
917
|
|| *lang == Lang::Mise
|
|
891
918
|
|| *lang == Lang::Terraform
|
|
919
|
+
|| *lang == Lang::DotNet
|
|
892
920
|
{
|
|
893
921
|
continue;
|
|
894
922
|
}
|
|
@@ -899,7 +927,7 @@ async fn run_audit(cli: &Cli) -> Result<()> {
|
|
|
899
927
|
Lang::Rust => Ecosystem::CratesIo,
|
|
900
928
|
Lang::Go => Ecosystem::Go,
|
|
901
929
|
Lang::Ruby => Ecosystem::RubyGems,
|
|
902
|
-
Lang::Actions | Lang::PreCommit | Lang::Mise | Lang::Terraform => {
|
|
930
|
+
Lang::Actions | Lang::PreCommit | Lang::Mise | Lang::Terraform | Lang::DotNet => {
|
|
903
931
|
unreachable!("filtered above")
|
|
904
932
|
}
|
|
905
933
|
};
|
|
@@ -1054,6 +1082,7 @@ fn print_alignment(alignment: &PackageAlignment, _dry_run: bool) {
|
|
|
1054
1082
|
Lang::Rust => " (cargo)",
|
|
1055
1083
|
Lang::Go => " (go)",
|
|
1056
1084
|
Lang::Ruby => " (rubygems)",
|
|
1085
|
+
Lang::DotNet => " (nuget)",
|
|
1057
1086
|
Lang::Actions => " (actions)",
|
|
1058
1087
|
Lang::PreCommit => " (pre-commit)",
|
|
1059
1088
|
Lang::Mise => " (mise)",
|
|
@@ -1187,6 +1216,9 @@ fn apply_version_updates(
|
|
|
1187
1216
|
FileType::ToolVersions => {
|
|
1188
1217
|
replace_tool_versions_version(&result, package, old_version, &target_version)
|
|
1189
1218
|
}
|
|
1219
|
+
FileType::Csproj => {
|
|
1220
|
+
replace_csproj_version(&result, package, old_version, &target_version)
|
|
1221
|
+
}
|
|
1190
1222
|
FileType::TerraformTf => {
|
|
1191
1223
|
replace_terraform_version(&result, package, old_version, &target_version)
|
|
1192
1224
|
}
|
|
@@ -1304,6 +1336,27 @@ fn replace_gemfile_version(content: &str, package: &str, old: &str, new: &str) -
|
|
|
1304
1336
|
.to_string()
|
|
1305
1337
|
}
|
|
1306
1338
|
|
|
1339
|
+
fn replace_csproj_version(content: &str, package: &str, old: &str, new: &str) -> String {
|
|
1340
|
+
// Pattern: <PackageReference Include="package" Version="old" />
|
|
1341
|
+
// and: <PackageVersion Include="package" Version="old" />
|
|
1342
|
+
let pattern = format!(
|
|
1343
|
+
r#"(<(?:PackageReference|PackageVersion)\s+Include="{}"[^>]*Version="){}"#,
|
|
1344
|
+
regex::escape(package),
|
|
1345
|
+
regex::escape(old)
|
|
1346
|
+
);
|
|
1347
|
+
let re = regex::Regex::new(&pattern).unwrap();
|
|
1348
|
+
let mut result = re
|
|
1349
|
+
.replace_all(content, format!(r#"${{1}}{}"#, new))
|
|
1350
|
+
.to_string();
|
|
1351
|
+
|
|
1352
|
+
// Also handle <Version>old</Version> child element for the given package
|
|
1353
|
+
let old_element = format!("<Version>{}</Version>", old);
|
|
1354
|
+
let new_element = format!("<Version>{}</Version>", new);
|
|
1355
|
+
result = result.replacen(&old_element, &new_element, 1);
|
|
1356
|
+
|
|
1357
|
+
result
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1307
1360
|
fn replace_github_actions_version(content: &str, package: &str, old: &str, new: &str) -> String {
|
|
1308
1361
|
let pattern = format!(
|
|
1309
1362
|
r#"({}@){}(\s|$|#|")"#,
|