Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ make ci # CI と同じ検査 (fmt-check + lint + test、書き換
- Bun Catalogs は root `package.json` のトップレベル `catalog` / `catalogs` と `workspaces.catalog` / `workspaces.catalogs` を解析・更新する。workspace package 側の `catalog:` / `catalog:<name>` 参照は、参照先 catalog 定義で一元管理されるため書き換えず保持する。複数の catalog object を更新するときは、JSON 内の出現順に範囲をソートしてから後方順に置換し、先行置換による byte offset のずれで後続 catalog を壊さない。pnpm の `pnpm-workspace.yaml` catalogs は現時点では未対応で、`package.json` 内の `catalog:` 参照は安全側でスキップする
- 同じマニフェストキーの依存が複数箇所に宣言されている場合 (Cargo.toml の `[dependencies]` + `[dev-dependencies]`、package.json の dependencies + devDependencies、pyproject の main + dev group、Gemfile の通常宣言 + `group :test` 等)、名前だけでは更新位置を一意に決められないため writer は曖昧な更新を拒否する。複数の Gradle 依存が同じバージョン変数または version catalog の `version.ref` を共有する場合も last-write-wins を避けて拒否し、スキップ・固定された別宣言を暗黙に書き換えない。拒否のエラーは、同じ依存キーの宣言が別々の更新になっても依存キーごとに 1 行だけ出す。git 依存の branch / rev / 既定ブランチの更新は Cargo.toml を書き換えないので、曖昧判定より前に抜けて拒否しない
- Cargo.toml では、取得元と版の指定が一致する宣言を parse の段階で 1 依存にまとめる (`CargoDeclarations`。Gradle の `push_unique_declaration` と同じ考え方)。dev 側にだけ `features` を足して同じ依存を `[dependencies]` と `[dev-dependencies]` に書く構成は Rust でよくあり、宣言ごとに 1 依存を返すと writer の曖昧性ガードに必ず掛かって「2 updates」と表示しながら 1 バイトも書けず exit code 2 になっていた (更新の行とエラーも宣言の数だけ並んでいた)。`update_version` / `update_git_tag` は全依存セクションの同名の宣言をすべて書き換えるので、まとめた 1 依存の 1 回の書き換えで全宣言が新しい版になる。キーは実パッケージ名・依存キー・版の指定の生表記・git の取得元 (URL・参照・公開用に併記した `version`)。生表記で比べるので `"1.0"` と `"^1.0"` はまとめない (writer が拒否する)。`features` などの付帯指定と `is_dev` はキーに含めず、`is_dev` はどれか 1 つでも本番の宣言があれば本番にする (`[dev-dependencies]` が target 固有の `[dependencies]` より先に読まれるため、最初の宣言を残すだけだと本番の依存が dev 扱いになる)
- マニフェストへ書き込めなかった更新 (曖昧として拒否・`update_version` / `update_git_tag` の失敗・読み込みや保存の失敗) は、更新として数えずに別に数える。writer は `WriteResult::failed_updates` に `results` 上の位置と理由を記録し、orchestrator の `write_phase` が `UpdateResult::Update` の `write_error` へ書き込む。summary は書き込み前後で意味を分け、`judged_updates()` / `has_judged_updates()` は judge が決めた更新 (writer が使う)、`updates()` / `update_count()` / `has_updates()` は書き込めなかった更新を除いたもの (出力・install・Rust の lock 監査が使う)、`failed_updates()` / `failed_count()` / `total_failed()` は書き込めなかった更新。件数は「judge が決めた更新 − 書き込めなかった更新」で数え、`updates_applied` は使わない (使うと Cargo.toml を書き換えない git の branch 依存や、書き換えても内容が同じ更新が 0 件になる)。以前は check の段階の件数をそのまま出していたので、1 バイトも書けていないのに「2 package(s) updated」と出ていた。出力は 3 種で数え方を揃える: テキストは見出し `— N updates, K failed, M skips`・行末の `✗ failed` (色なしは `[failed]`)・Summary の `K package(s) failed to update`・`-q` の `N updated, K failed`、JSON は `summary.failed` と各マニフェストの `failed` 配列 (要素に `error`。`updates` からは外す)、diff は hunk を出さず件数行に `, K failed`。全更新を書き込めなかったマニフェストは install の理由にせず (Rust の install は lock 全体を上げる `cargo update`)、Rust の lock 監査も書き込めなかった更新先を「表示した更新先」(差し戻し先の候補・食い違いの注記) に使わない。保存 (I/O) の失敗でも `apply_updates` は `Ok` を返し、保存前に個別の理由で失敗した更新はその理由を残す (`Err` は読み込み・解析に失敗してどの更新も試せなかったときだけ)
- Cargo.toml の複数行テーブル (`[dependencies.<pkg>]`) はセクション追跡の行ベースで更新され、`features = [...]` が `version` より前にあるキー順でも、テーブル内コメントに `version = "..."` 文字列があっても正しく動く。`update_git_tag` は inline table と複数行 `tag` の両方で同方式を使い、依存/patch セクション外の同名キーを触らず、単一引用符も保持する
- Package.swift の URL マッチは末尾境界付き (`grpc/grpc-swift` の更新が `grpc/grpc-swift-nio` の宣言に前方一致しない)
- Composer は `~>` を拒否する (composer/semver の tilde 分岐は正規表現 `{^~>?<version>$}i` にマッチした**後**に `Invalid operator "~>"` を throw する) ため、PHP パーサは `~>` を parse 時点でスキップする。受理すると「更新しました」と報告しつつ composer が読めない制約を書き戻すことになる。node-semver は `LONETILDE = (?:~>?)` で `~>` を valid とするので Node パーサは従来どおり受理し、更新後も綴りを保つ (言語間で挙動が違うのは仕様差によるもの)
Expand Down
50 changes: 37 additions & 13 deletions docs/cli-reference.ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ depup --cd ./projects/myapp -n
- 変更の種類は `[major]` / `[minor]` / `[patch]` で示します。
- `✓ OSV` は、脆弱性チェックを通過したバージョンに付きます。更新行の下の `↳ OSV skipped:` 行には、脆弱性があるため候補から外したバージョンを表示します。ラベルは skipped ですが、依存のスキップではありません(依存そのものは更新されています)。
- スキップした依存の件数は、マニフェストの見出し(`— N updates, M skips`)と Summary に表示します。更新が 0 件のマニフェストでは、理由ごとの件数も表示します。
- マニフェストへ書き込めなかった更新(書き込み先が曖昧なための拒否など)は、行末に `✗ failed` が付き、更新の件数に入りません。見出しは `— N updates, K failed, M skips` になり、Summary に `K package(s) failed to update` の行が加わります。理由は `Errors:` 欄に表示します。
- `--verbose` を付けると、スキップした依存を理由ごとに一覧し、Summary にも理由別・言語別の内訳を付けます。
- エラーは、OSV の通知も含めて `Errors:` 欄に表示します。

Expand All @@ -109,40 +110,63 @@ depup --json

```json
{
"dry_run": false,
"summary": {
"updates": 1,
"failed": 1,
"skips": 1
},
"manifests": [
{
"path": "package.json",
"language": "node",
"path": "./package.json",
"language": "Node.js",
"updates": [
{
"type": "update",
"dependency": {
"name": "lodash",
"version_spec": "^4.17.20"
},
"new_version": "4.17.21",
"released_at": "2024-12-15T10:30:00Z"
"name": "lodash",
"kind": "registry",
"from": "4.17.20",
"to": "4.17.21",
"dev": false
}
],
"failed": [
{
"name": "react",
"kind": "registry",
"from": "18.0.0",
"to": "19.2.0",
"dev": false,
"error": "Refusing to update ambiguous dependency 'react' because it has multiple declarations or a shared version target"
}
]
}
],
"errors": [
"Failed to write ./package.json: Refusing to update ambiguous dependency 'react' because it has multiple declarations or a shared version target"
]
}
```

`summary.updates` と各マニフェストの `updates` に入るのは、書き込めた更新(`--dry-run` では書き込める見込みの更新)だけです。書き込めなかった更新は `summary.failed` に数え、マニフェストの `failed` 配列に入れて、理由を `error` に入れます。git 依存は `"kind": "git"` になり、`source`(認証情報を伏せたリポジトリの URL)と `reference` が加わります。`--verbose` を付けると、各マニフェストに `skips` が、`summary` に `by_language` が加わります。

### diff 出力

```bash
depup --diff
```

```diff
--- package.json
+++ package.json
@@ dependencies @@
--- a/./package.json
+++ b/./package.json
@@ lodash @@
- "lodash": "^4.17.20"
+ "lodash": "^4.17.21"

# 1 package(s) would be updated, 1 failed
```

書き込めなかった更新の hunk は出しません。最後の行の件数はテキスト・JSON の出力と同じ数え方で、書き込めなかった更新があるときだけ `, K failed` を付けます。

### 終了コード

| コード | 意味 |
Expand All @@ -151,7 +175,7 @@ depup --diff
| `1` | パッケージマネージャーの install が失敗した、`--cd` でディレクトリを移動できなかった、または depup 自体が動作を続けられなかった(HTTP クライアントの初期化や、結果の出力に失敗した場合など) |
| `2` | 処理の一部が失敗した。マニフェストの読み込み・解析・書き込みの失敗(書き込み先が曖昧なための拒否を含む)、レジストリからの取得の失敗、Rust または Node の lock の age 監査で違反・未確認が残る場合(lock の読み込み失敗や時間切れを含む)が該当する。コマンドライン引数の誤りも `2` になる |

終了コード 2 になる失敗が起きても、処理は止まりません。取得に失敗した依存はスキップし、読み込みや解析に失敗したマニフェストは処理から外して、それ以外の書き込みや install は続けます。書き込みに失敗したファイルは元のまま残りますが、その依存は更新として表示され、`--install` も実行されます。`1` と `2` の両方に当てはまる場合は `1` になります。
終了コード 2 になる失敗が起きても、処理は止まりません。取得に失敗した依存はスキップし、読み込みや解析に失敗したマニフェストは処理から外して、それ以外の書き込みや install は続けます。ファイルの保存に失敗した場合は、元の内容のまま残ります。マニフェストの一部の更新だけを書き込めなかった場合(書き込み先が曖昧なための拒否など)は、残りの更新を保存します。どちらの場合も、書き込めなかった更新は失敗として表示し、`--install` を実行する理由にもしません。`1` と `2` の両方に当てはまる場合は `1` になります。

取得の問題のうち、次の 3 つは終了コードを変えません。

Expand Down
50 changes: 37 additions & 13 deletions docs/cli-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ depup --cd ./projects/myapp -n
- Change type: `[major]`, `[minor]`, `[patch]`
- `✓ OSV` marks versions that passed the vulnerability check. A `↳ OSV skipped:` line below an update lists the vulnerable versions that were removed from the candidates; the dependency itself was still updated
- Skipped dependencies are counted in each manifest heading (`— N updates, M skips`) and in the summary; a manifest with no updates also shows the count per reason
- An update that could not be written to the manifest (for example, a write refused as ambiguous) ends with `✗ failed` and is not counted as an update: the heading becomes `— N updates, K failed, M skips`, and the summary adds `K package(s) failed to update`. The reason is listed in the `Errors:` section
- With `--verbose`, every skipped dependency is listed under its reason, and the summary is broken down by reason and language
- Errors, including OSV notices, are listed in the `Errors:` section

Expand All @@ -109,40 +110,63 @@ depup --json

```json
{
"dry_run": false,
"summary": {
"updates": 1,
"failed": 1,
"skips": 1
},
"manifests": [
{
"path": "package.json",
"language": "node",
"path": "./package.json",
"language": "Node.js",
"updates": [
{
"type": "update",
"dependency": {
"name": "lodash",
"version_spec": "^4.17.20"
},
"new_version": "4.17.21",
"released_at": "2024-12-15T10:30:00Z"
"name": "lodash",
"kind": "registry",
"from": "4.17.20",
"to": "4.17.21",
"dev": false
}
],
"failed": [
{
"name": "react",
"kind": "registry",
"from": "18.0.0",
"to": "19.2.0",
"dev": false,
"error": "Refusing to update ambiguous dependency 'react' because it has multiple declarations or a shared version target"
}
]
}
],
"errors": [
"Failed to write ./package.json: Refusing to update ambiguous dependency 'react' because it has multiple declarations or a shared version target"
]
}
```

`summary.updates` and each manifest's `updates` cover only the updates that were written (with `--dry-run`, the updates that would be written). Updates that could not be written are counted in `summary.failed` and listed in the manifest's `failed` array, with the reason in `error`. Git dependencies use `"kind": "git"` and add `source` (the repository URL with any credentials masked) and `reference`. With `--verbose`, each manifest also lists its `skips`, and the summary adds `by_language`.

### Diff Output

```bash
depup --diff
```

```diff
--- package.json
+++ package.json
@@ dependencies @@
--- a/./package.json
+++ b/./package.json
@@ lodash @@
- "lodash": "^4.17.20"
+ "lodash": "^4.17.21"

# 1 package(s) would be updated, 1 failed
```

Updates that could not be written get no hunk. The last line counts updates the same way as the text and JSON output, and adds `, K failed` only when some updates could not be written.

### Exit Codes

| Code | Meaning |
Expand All @@ -151,7 +175,7 @@ depup --diff
| `1` | A package manager install failed, `--cd` could not change the directory, or depup itself could not continue (for example, the HTTP client failed to initialize or the results could not be written). |
| `2` | Part of the run failed: a manifest could not be read, parsed, or written (including a refused ambiguous write), a registry lookup failed, or a Rust or Node lockfile age audit left violations or unverified entries (including an unreadable lock or an exhausted time budget). Invalid command-line arguments also exit with `2`. |

A code-2 failure does not stop the run. A failed lookup skips that dependency, and a manifest that cannot be read or parsed is left out; everything else is still written and installed. A failed write leaves that file unchanged, but its dependencies are still listed as updated and `--install` still runs for it. When both `1` and `2` apply, `1` wins.
A code-2 failure does not stop the run. A failed lookup skips that dependency, and a manifest that cannot be read or parsed is left out; everything else is still written and installed. If a file cannot be saved, it keeps its original content. If only some updates in a manifest cannot be written (for example, one refused as ambiguous), the rest are still saved. Either way, the updates that could not be written are reported as failed instead of updated, and they do not make `--install` run. When both `1` and `2` apply, `1` wins.

These lookup problems leave the exit code unchanged:

Expand Down
4 changes: 3 additions & 1 deletion docs/usage.ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ depup が書き換えるのは、解析した依存宣言だけです。依存

`--install` を指定すると、depup はマニフェストを書き換えたあと、プロジェクトごとにパッケージマネージャーを実行します。ロックファイルやインストール済みのパッケージを、新しいバージョンに合わせるためです。

- install を実行するのは、1 件以上更新したマニフェストだけです。`--dry-run` のときは実行しません。
- install を実行するのは、1 件以上更新したマニフェストだけです。`--dry-run` のときは実行しません。マニフェストへ書き込めなかった更新は数えません。
- Node は pnpm workspace の共有ルート、またはマニフェストのあるディレクトリで install を実行します。他言語は [`.depup`](configuration.ja.md#depup-設定ファイル) がなければ対象ディレクトリ(PATH 引数)を使い、あれば更新したマニフェストを含む対象のうち最も深いディレクトリを使います。
- install は 1 つずつ、ディレクトリのパス順に実行します。同じディレクトリでは、言語ごとに 1 回だけです。パッケージマネージャーの出力は画面に流さずに depup が受け取り、標準エラー出力は install が失敗したときだけ表示します。

Expand Down Expand Up @@ -506,4 +506,6 @@ Python プロジェクトで `--install` が `uv sync` を呼び出すとき、d

表の理由はテキスト出力の表記です。`--verbose` を付けた `--json` の出力では、同じ理由が `already_latest`、`pinned`、`change_level_limited: <LEVEL>`、`excluded`、`not_in_only_list`、`no_suitable_version`、`parse_error: ...`、`fetch_failed: ...` と表記されます。

行末に `✗ failed`(色なしでは `[failed]`)が付いた更新の行は、depup が見つけたもののマニフェストへ書き込めなかった更新です。書き込み先が曖昧で拒否した場合などがこれにあたります([書き込みの共通原則](#書き込みの共通原則)を参照)。更新ではなく失敗として数え、理由は `Errors:` 欄に出し、終了コードは `2` になります。

依存が出力にまったく現れない場合、depup はその宣言を対象外にしています。ファイル・セクション・宣言の書き方が対応しているかを、[エコシステム別の詳細](ecosystems.ja.md#エコシステム別の詳細)で確認してください。`--node` のように言語を指定した場合、指定していない言語のマニフェストは解析しません(pnpm・Bun・mise の age 設定だけは読み取ります)。マニフェストは更新されたのに install が失敗した場合は、[パッケージマネージャーの実行](#パッケージマネージャーの実行--install)を参照してください。
Loading
Loading