pyfltr 3.3.0__tar.gz → 3.3.2__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.
- {pyfltr-3.3.0 → pyfltr-3.3.2}/.pre-commit-config.yaml +6 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/CLAUDE.md +3 -4
- {pyfltr-3.3.0 → pyfltr-3.3.2}/PKG-INFO +1 -1
- {pyfltr-3.3.0 → pyfltr-3.3.2}/docs/development/development.md +0 -20
- {pyfltr-3.3.0 → pyfltr-3.3.2}/docs/development/jsonl-output.md +4 -3
- {pyfltr-3.3.0 → pyfltr-3.3.2}/docs/guide/configuration-tools.md +19 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/docs/guide/configuration.md +1 -1
- {pyfltr-3.3.0 → pyfltr-3.3.2}/docs/guide/usage.md +6 -5
- {pyfltr-3.3.0 → pyfltr-3.3.2}/mkdocs.yml +2 -2
- {pyfltr-3.3.0 → pyfltr-3.3.2}/pyfltr/command.py +26 -9
- {pyfltr-3.3.0 → pyfltr-3.3.2}/pyfltr/config.py +5 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/pyfltr/llm_output.py +19 -15
- {pyfltr-3.3.0 → pyfltr-3.3.2}/pyfltr/main.py +34 -4
- {pyfltr-3.3.0 → pyfltr-3.3.2}/tests/command_core_test.py +161 -2
- {pyfltr-3.3.0 → pyfltr-3.3.2}/tests/config_test.py +20 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/tests/llm_output_test.py +47 -17
- {pyfltr-3.3.0 → pyfltr-3.3.2}/tests/output_format_test.py +55 -13
- {pyfltr-3.3.0 → pyfltr-3.3.2}/.claude/agents/error-parser-reviewer.md +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/.claude/agents/tool-compat-checker.md +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/.claude/skills/pyfltr-add-tool/SKILL.md +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/.editorconfig +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/.gitattributes +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/.github/workflows/ci.yaml +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/.github/workflows/docs.yaml +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/.github/workflows/release.yaml +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/.gitignore +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/.gitmessage +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/.markdownlint-cli2.yaml +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/.npmrc +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/.pylintrc +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/.python-version +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/.textlintignore +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/.textlintrc.yaml +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/.vscode/extensions.json +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/.vscode/settings.json +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/LICENSE +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/Makefile +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/README.md +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/cliff.toml +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/docs/.markdownlint-cli2.yaml +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/docs/development/architecture.md +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/docs/development/archive-and-cache.md +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/docs/development/index.md +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/docs/development/mcp-server.md +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/docs/development/subcommands.md +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/docs/guide/custom-commands.md +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/docs/guide/index.md +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/docs/guide/migration-v3.md +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/docs/guide/recommended-nonpython.md +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/docs/guide/recommended.md +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/docs/index.md +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/mise.toml +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/pyfltr/__init__.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/pyfltr/__main__.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/pyfltr/archive.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/pyfltr/builtin_commands.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/pyfltr/cache.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/pyfltr/cli.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/pyfltr/code_quality.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/pyfltr/error_parser.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/pyfltr/executor.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/pyfltr/formatters.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/pyfltr/github_annotations.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/pyfltr/mcp_.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/pyfltr/only_failed.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/pyfltr/paths.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/pyfltr/precommit.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/pyfltr/presets.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/pyfltr/retry.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/pyfltr/rule_urls.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/pyfltr/runs.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/pyfltr/sarif_output.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/pyfltr/shell_completion.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/pyfltr/stage_runner.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/pyfltr/ui.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/pyfltr/warnings_.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/pyproject.toml +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/tests/__init__.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/tests/archive_test.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/tests/cache_test.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/tests/cli_test.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/tests/code_quality_test.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/tests/command_linter_fix_test.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/tests/command_prettier_test.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/tests/command_ruff_format_test.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/tests/command_textlint_fix_test.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/tests/conftest.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/tests/error_parser_test.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/tests/executor_test.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/tests/github_annotations_test.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/tests/main_test.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/tests/mcp_test.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/tests/only_failed_test.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/tests/paths_test.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/tests/precommit_test.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/tests/retry_test.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/tests/rule_urls_test.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/tests/runs_test.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/tests/sarif_output_test.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/tests/shell_completion_test.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/tests/stage_runner_test.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/tests/ui_test.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/tests/warnings_test.py +0 -0
- {pyfltr-3.3.0 → pyfltr-3.3.2}/uv.lock +0 -0
|
@@ -32,3 +32,9 @@ repos:
|
|
|
32
32
|
types_or: [python, markdown, toml]
|
|
33
33
|
require_serial: true
|
|
34
34
|
language: system
|
|
35
|
+
- id: mkdocs-build
|
|
36
|
+
name: mkdocs build --strict
|
|
37
|
+
entry: uv run --frozen mkdocs build --strict --quiet --site-dir /tmp/mkdocs-check
|
|
38
|
+
language: system
|
|
39
|
+
pass_filenames: false
|
|
40
|
+
files: ^(docs/|mkdocs\.yml|README\.md|CLAUDE\.md)
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
- `make update`: 依存更新 + pre-commit autoupdate + pinactアクション更新 + 全テスト実行
|
|
6
6
|
- `make update-actions`: GitHub Actionsのハッシュピン更新のみ(mise経由でpinact実行)
|
|
7
|
+
- リリース手順: [docs/development/development.md](docs/development/development.md) 参照
|
|
7
8
|
- テストコードは`pyfltr/xxx_.py`に対して`tests/xxx_test.py`として配置する
|
|
8
9
|
- コミット前の検証方法: `uv run pyfltr run-for-agent`
|
|
9
10
|
- ドキュメントなどのみの変更の場合は省略可(pre-commitで実行されるため)
|
|
@@ -36,13 +37,11 @@ stdout占有は`jsonl` / `sarif` / `code-quality`かつ`--output-file`未指定
|
|
|
36
37
|
|
|
37
38
|
## 注意点
|
|
38
39
|
|
|
39
|
-
-
|
|
40
|
-
|
|
41
|
-
- 内部リンクは英数アンカーを優先する。MkDocs(Material)のslugifyは英数のみを採用してアンカー生成する。
|
|
40
|
+
- 内部リンクは英数アンカーを優先する。MkDocs(Material)のslugifyは英数のみを採用してアンカー生成するため、
|
|
41
|
+
日本語アンカーリンク`#見出し日本語`はTOCで解決できずINFO通知のみで`--strict`でも検知されない(手動確認要)。
|
|
42
42
|
markdownlint MD051は見出し原文を見るため、`{#id}`記法で明示併設する(例:「### jsonl形式の使い方 {#jsonl}」)
|
|
43
43
|
- `docs/guide/index.md`の対応ツール一覧と`mkdocs.yml`内llmstxt `markdown_description`の「対応ツール」節は
|
|
44
44
|
人手同期(SSOT化しない運用)
|
|
45
45
|
- `mkdocs.yml`内llmstxt `markdown_description`にはLLMが利用する際に有用な情報のみ記載する
|
|
46
46
|
(`run-for-agent`サブコマンド、主要オプションなど)。LLMにとって不要な情報はdocs側をSSOTとし、多重管理を避ける
|
|
47
|
-
- ドキュメント構成変更時は`docs/development/development.md`の「READMEとdocsの役割分担」節を先に参照
|
|
48
47
|
- JSONLスキーマの変更は破壊的変更扱いしない(LLMが読みやすいよう継続的に改善する)
|
|
@@ -34,22 +34,6 @@ CI/`make`などの自動実行環境で`uv sync`/`uv run`が依存解決を再
|
|
|
34
34
|
`uv add`/`uv remove`/`uv lock --upgrade-package`を使えばよい。
|
|
35
35
|
`make update`も内部で自動的にUV_FROZENを外すため、そのまま実行してよい。
|
|
36
36
|
|
|
37
|
-
## READMEとdocsの役割分担
|
|
38
|
-
|
|
39
|
-
本プロジェクトのドキュメントは以下の構成で配置している。
|
|
40
|
-
|
|
41
|
-
- README.md: 概要・特徴・インストール手順・ドキュメントへのリンクを網羅する「玄関」。
|
|
42
|
-
README.mdだけを読めばプロジェクトの目的と使い始めるための入口が把握できる状態を保つ
|
|
43
|
-
- docs/guide/: 利用者向けの詳細情報(対応ツール一覧・コンセプト・設定リファレンス・使い方など)
|
|
44
|
-
- docs/development/: 開発者向けの情報(セットアップ・リリース手順など)
|
|
45
|
-
|
|
46
|
-
README.mdとdocs側で概要・特徴・インストール手順が部分的に重複する場合があるが、README.mdはGitHubトップとして、
|
|
47
|
-
docs側は公開ドキュメントの入口としてそれぞれ自己完結する必要があるため、この重複は許容する。
|
|
48
|
-
本プロジェクトの`docs/index.md`はREADMEへの参照のみに留めており、インストール手順の重複は発生させていない。
|
|
49
|
-
|
|
50
|
-
変更頻度が低いため二重管理のコストより一貫性・可読性のメリットが上回ると判断した。
|
|
51
|
-
変更時は、docs側で同じ情報を再掲している箇所があれば同じコミット内で合わせて更新する。
|
|
52
|
-
|
|
53
37
|
## ドキュメント
|
|
54
38
|
|
|
55
39
|
ドキュメントはMkDocsで管理し、GitHub Pagesでホスティングしている。
|
|
@@ -72,10 +56,6 @@ uv run mkdocs serve
|
|
|
72
56
|
|
|
73
57
|
masterブランチへのpush時にdocs/配下やmkdocs.ymlの変更があると自動デプロイされる。
|
|
74
58
|
|
|
75
|
-
## コミットメッセージ(Conventional Commits)
|
|
76
|
-
|
|
77
|
-
Conventional Commits形式に従う。ただし記述の方向性があまり変わらないような軽微な修正は`chore`などにしてよい。
|
|
78
|
-
|
|
79
59
|
## リリース手順
|
|
80
60
|
|
|
81
61
|
事前に`gh`コマンドをインストールして`gh auth login`でログインしておき、以下のコマンドのいずれかを実行。
|
|
@@ -7,7 +7,7 @@ LLMエージェントとCIシステム向けに提供するJSONL出力(およ
|
|
|
7
7
|
|
|
8
8
|
| `kind` | 役割 |
|
|
9
9
|
| --- | --- |
|
|
10
|
-
| `header` | 先頭1行。実行環境情報。`
|
|
10
|
+
| `header` | 先頭1行。実行環境情報。`commands`は実行対象(有効化された)コマンド名配列。`schema_hints`は既定で短縮版、`-v`指定時にフル版へ切り替わる |
|
|
11
11
|
| `warning` | pyfltrが検出した設定・実行時の警告(`source`で発生元を識別) |
|
|
12
12
|
| `diagnostic` | `(command, file)`単位で集約された診断。個別指摘は`messages[]`配列に格納 |
|
|
13
13
|
| `command` | 1コマンド1レコードの実行メタ情報。rule→URL辞書`hint-urls`をオプションで含む |
|
|
@@ -29,10 +29,11 @@ JSONLはLLMエージェントが入力として読むケースが多いため、
|
|
|
29
29
|
英語にするのはトークン効率(日本語より短くなりやすい)と汎用性(LLMの入力として標準的)のため。
|
|
30
30
|
|
|
31
31
|
- `header.schema_hints`: 毎runに付与する英語の辞書。既定はLLMが読み違いやすい非自明フィールドのみに絞った短縮版を出す。
|
|
32
|
-
実装は`_SCHEMA_HINTS_COMPACT`で約
|
|
32
|
+
実装は`_SCHEMA_HINTS_COMPACT`で約400文字。
|
|
33
33
|
`-v` / `--verbose`指定時はフル版`_SCHEMA_HINTS`(約1,500文字)に切り替わり、
|
|
34
34
|
`diagnostic.messages` / `diagnostic.messages.fix` / `diagnostic.messages.severity` /
|
|
35
|
-
`command.hint-urls` / `command.retry_command` / `command.cached` / `command.
|
|
35
|
+
`command.hint-urls` / `command.retry_command` / `command.cached` / `command.cached_elapsed` /
|
|
36
|
+
`command.truncated` / `header.run_id`
|
|
36
37
|
などフィールド単位の詳細を英文で説明する。
|
|
37
38
|
短縮版には`_note`キーでフル版の取得方法を案内する。
|
|
38
39
|
公開窓口は`pyfltr/llm_output.py`の`get_schema_hints(full=...)`
|
|
@@ -349,6 +349,25 @@ GitHub ActionsでCIを実行する場合は[jdx/mise-action](https://github.com/
|
|
|
349
349
|
|
|
350
350
|
miseを使わず、PATH上のバイナリを直接使う場合は`bin-runner = "direct"`を設定する。
|
|
351
351
|
|
|
352
|
+
### mise-auto-trust
|
|
353
|
+
|
|
354
|
+
`mise`モードでは、worktreeやdotfiles配下のディレクトリなど、`mise.toml`が未信頼扱いになっている場合に
|
|
355
|
+
事前チェックが失敗することがある。
|
|
356
|
+
既定では`mise-auto-trust = true`となっており、未信頼configを検出すると`mise trust --yes --all`を自動実行して
|
|
357
|
+
信頼を確立してからリトライする。
|
|
358
|
+
`--all`オプションはcwdおよびその親ディレクトリにある全configを対象とするため、
|
|
359
|
+
プロジェクト外の親ディレクトリに`mise.toml`が存在する場合もまとめて信頼される点に注意する。
|
|
360
|
+
|
|
361
|
+
`mise-auto-trust`が不要な場合は無効化できる。
|
|
362
|
+
|
|
363
|
+
```toml
|
|
364
|
+
[tool.pyfltr]
|
|
365
|
+
mise-auto-trust = false
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
無効化した場合、未信頼configが原因の失敗はmise由来のエラーメッセージとともに`failed`扱いとなる。
|
|
369
|
+
手動で`mise trust`を実行して対処する。
|
|
370
|
+
|
|
352
371
|
### バージョン指定
|
|
353
372
|
|
|
354
373
|
`{command}-version`でbin-runner対応ツールのバージョンを指定できる。既定は`"latest"`。
|
|
@@ -222,6 +222,8 @@ pyfltr ci --commands=ruff-check,markdownlint [files and/or directories ...]
|
|
|
222
222
|
```
|
|
223
223
|
|
|
224
224
|
カンマ区切りで実行するツールだけ指定する。全サブコマンドで使用可能。
|
|
225
|
+
`--commands`は複数回指定も可能で、カンマ区切りと併用できる。
|
|
226
|
+
例えば`--commands=mypy --commands=pyright,ruff-check`は`--commands=mypy,pyright,ruff-check`と同じになる。
|
|
225
227
|
|
|
226
228
|
以下のエイリアスも使用可能。(例: `--commands=format`)
|
|
227
229
|
|
|
@@ -330,10 +332,9 @@ CLIオプション`--output-format`が指定されている場合は環境変数
|
|
|
330
332
|
出力は以下5種別のレコードからなる。`kind`フィールドでレコード種別を判別する。
|
|
331
333
|
|
|
332
334
|
- `header`: 先頭1行。実行環境情報
|
|
333
|
-
(`version` / `run_id` / `python` / `executable` / `platform` / `cwd` / `
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
フル`commands`配列は実行アーカイブの`meta.json`に常時保存されるため、短縮時も`show-run <run_id>`で参照できる
|
|
335
|
+
(`version` / `run_id` / `python` / `executable` / `platform` / `cwd` / `commands` / `files` / `schema_hints`)。
|
|
336
|
+
`commands`は実行対象(有効化された、`--only-failed`適用後の)コマンド名配列。
|
|
337
|
+
既定は短縮版`schema_hints`(約400文字)。`-v` / `--verbose`指定時は`schema_hints`をフル版(約1,500文字)へ切り替える
|
|
337
338
|
- `warning`: pyfltrが検出した設定・実行時の警告(`source`で発生元を識別)
|
|
338
339
|
- `diagnostic`: `(command, file)`単位で集約された診断。個別指摘は`messages[]`配列に格納
|
|
339
340
|
- `command`: 1コマンド1レコードの実行メタ情報
|
|
@@ -343,7 +344,7 @@ CLIオプション`--output-format`が指定されている場合は環境変数
|
|
|
343
344
|
[`pyfltr show-run`](#show-run) / [`pyfltr list-runs`](#list-runs)で該当runの詳細を参照できる。
|
|
344
345
|
|
|
345
346
|
```json
|
|
346
|
-
{"kind":"header","version":"3.0.0","run_id":"01HXYZ...","python":"3.12.0 ...","executable":"/usr/bin/python3","platform":"linux","cwd":"/work","
|
|
347
|
+
{"kind":"header","version":"3.0.0","run_id":"01HXYZ...","python":"3.12.0 ...","executable":"/usr/bin/python3","platform":"linux","cwd":"/work","commands":["mypy","ruff-format"],"files":12,"schema_hints":{"header":"...","_note":"full schema available with -v / --verbose ..."}}
|
|
347
348
|
{"kind":"warning","source":"config","msg":"pre-commit が有効化されていますが、設定ファイルが見つかりません: .pre-commit-config.yaml"}
|
|
348
349
|
{"kind":"diagnostic","command":"mypy","file":"src/a.py","messages":[{"line":42,"col":5,"msg":"Incompatible return value type"}]}
|
|
349
350
|
{"kind":"command","command":"mypy","type":"linter","status":"failed","files":12,"elapsed":0.8,"diagnostics":1,"rc":1}
|
|
@@ -72,10 +72,10 @@ plugins:
|
|
|
72
72
|
|
|
73
73
|
`--output-format=jsonl`でJSON Lines形式の構造化出力が得られる。レコードは5種類。
|
|
74
74
|
|
|
75
|
-
- `header`: 先頭1行。実行環境情報(`version` / `run_id` / `python` / `executable` / `platform` / `cwd` / `
|
|
75
|
+
- `header`: 先頭1行。実行環境情報(`version` / `run_id` / `python` / `executable` / `platform` / `cwd` / `commands` / `files` / `schema_hints`)。`commands` は実行対象(有効化された)コマンド名配列。既定では短縮版 `schema_hints` を出し、`-v` / `--verbose` 指定時にフル `schema_hints` へ切り替わる。`schema_hints` は各フィールドの意味を英語で補足する LLM 向けガイド
|
|
76
76
|
- `warning`: pyfltr が検出した設定・実行時の警告(`source` で発生元を識別)
|
|
77
77
|
- `diagnostic`: `(command, file)` 単位で1行に集約される診断。個別指摘は `messages[]` 配列(各要素は `line` / `col` / `rule` / `severity` / `fix` / `msg` / `hint`)として格納される。`fix` は `"safe"` / `"unsafe"` / `"suggested"` / `"none"` の4値を取り、ツールが自動修正情報を返さない場合はフィールドごと省略。`hint` は textlint の頻出ルールなど、pyfltr 側でヒントを事前登録したルールにのみ付与される
|
|
78
|
-
- `command`: ツールごとの実行結果サマリ(`status` / `elapsed` / `diagnostics` / `rc` / `retry_command` / `truncated` / `cached` / `cached_from` / `hint-urls`)。`hint-urls` は rule→ドキュメントURLの辞書
|
|
78
|
+
- `command`: ツールごとの実行結果サマリ(`status` / `elapsed` / `diagnostics` / `rc` / `retry_command` / `truncated` / `cached` / `cached_from` / `cached_elapsed` / `hint-urls`)。`cached=true` のとき `elapsed` は省略され前回実行時の計測値を `cached_elapsed` として提示する。`hint-urls` は rule→ドキュメントURLの辞書
|
|
79
79
|
- `summary`: 最終1行の全体集計(`succeeded` / `formatted` / `failed` / `skipped` / `diagnostics` / `exit`)。`failed > 0` のとき英語の `guidance` 配列を付与し、再実行コマンドや `show-run` の案内を返す。直接指定ファイルが `exclude` / `.gitignore` で全除外された場合は `fully_excluded_files` にパス一覧を付与する(非空時のみ)
|
|
80
80
|
|
|
81
81
|
stdoutモード(`--output-file`未指定)の出力順は`header`→ツール完了順に`diagnostic`+`command`→`warning`→`summary`。stdoutへJSONLのみを書き、進捗ログやTUIは無音化される。`--output-file`指定時はファイルへJSONLを書き、stdoutには従来どおりのテキスト出力を並行出力する(ローカル実行で進捗を追える)。
|
|
@@ -300,15 +300,32 @@ def _resolve_bin_commandline(
|
|
|
300
300
|
raise FileNotFoundError("mise")
|
|
301
301
|
tool_name = spec.mise_backend or spec.bin_name
|
|
302
302
|
tool_spec = f"{tool_name}@{version}"
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
303
|
+
check_args = ["mise", "exec", tool_spec, "--", spec.bin_name, "--version"]
|
|
304
|
+
trusted = False
|
|
305
|
+
while True:
|
|
306
|
+
# バージョン指定込みでツールの利用可否を事前チェック
|
|
307
|
+
check = subprocess.run(
|
|
308
|
+
check_args,
|
|
309
|
+
capture_output=True,
|
|
310
|
+
text=True,
|
|
311
|
+
check=False,
|
|
312
|
+
)
|
|
313
|
+
if check.returncode == 0:
|
|
314
|
+
break
|
|
315
|
+
stderr = check.stderr
|
|
316
|
+
# config未信頼が原因かつ自動trust有効なら1回だけ信頼してリトライ
|
|
317
|
+
if not trusted and config["mise-auto-trust"] and "not trusted" in stderr:
|
|
318
|
+
trust = subprocess.run(
|
|
319
|
+
["mise", "trust", "--yes", "--all"],
|
|
320
|
+
capture_output=True,
|
|
321
|
+
text=True,
|
|
322
|
+
check=False,
|
|
323
|
+
)
|
|
324
|
+
if trust.returncode == 0:
|
|
325
|
+
trusted = True
|
|
326
|
+
continue
|
|
327
|
+
raise FileNotFoundError(f"mise trust --yes --all: {trust.stderr.strip()}")
|
|
328
|
+
raise FileNotFoundError(f"mise exec {tool_spec} -- {spec.bin_name}: {stderr.strip()}")
|
|
312
329
|
return "mise", ["exec", tool_spec, "--", spec.bin_name]
|
|
313
330
|
|
|
314
331
|
raise ValueError(f"bin-runnerの設定値が正しくありません: {runner=}")
|
|
@@ -110,6 +110,11 @@ DEFAULT_CONFIG: dict[str, typing.Any] = {
|
|
|
110
110
|
# - mise: mise exec <tool>@<version> -- <cmd>(既定)
|
|
111
111
|
# - direct: PATH 上のバイナリを直接実行
|
|
112
112
|
"bin-runner": "mise",
|
|
113
|
+
# mise 実行時に対象ディレクトリの config が未信頼だった場合、
|
|
114
|
+
# 自動で ``mise trust --yes --all`` を実行して再試行するか。
|
|
115
|
+
# worktree や dotfiles 配下など mise.toml が未信頼扱いになりやすい
|
|
116
|
+
# 環境での手動介入を不要にするための opt-out 設定(既定は有効)。
|
|
117
|
+
"mise-auto-trust": True,
|
|
113
118
|
# コマンド毎に有効無効、パス、追加の引数を設定
|
|
114
119
|
# 言語カテゴリ (python / javascript / rust / dotnet) に属するツールは v3.0.0 で
|
|
115
120
|
# opt-in 化したため、既定値は False。preset で推奨ツールが True になり、
|
|
@@ -154,8 +154,8 @@ def build_lines(
|
|
|
154
154
|
``warnings``は``pyfltr.warnings_.collected_warnings()``の返り値を想定する。
|
|
155
155
|
``run_id``が指定されていればheaderレコードに埋め込む。
|
|
156
156
|
``launcher_prefix``が指定されていれば``summary.guidance``内の起動コマンド表記に反映する。
|
|
157
|
-
``verbose=True`` でheader
|
|
158
|
-
(
|
|
157
|
+
``verbose=True`` でheaderの``schema_hints``をフル版に切り替える
|
|
158
|
+
(既定は短縮版。``commands`` 配列は常に出力する)。
|
|
159
159
|
"""
|
|
160
160
|
ordered = sorted(results, key=lambda r: _command_index(config, r.command))
|
|
161
161
|
|
|
@@ -198,8 +198,7 @@ def write_jsonl_header(commands: list[str], files: int, *, run_id: str | None =
|
|
|
198
198
|
headerレコードに含める (アーカイブ参照時の識別キー)。
|
|
199
199
|
出力先は ``pyfltr.cli.configure_structured_output()`` が設定した handler に従う
|
|
200
200
|
(stdout もしくは `--output-file` の FileHandler)。
|
|
201
|
-
``verbose=True``
|
|
202
|
-
(既定は``commands_count``と短縮``schema_hints``でヘッダーサイズを抑制)。
|
|
201
|
+
``verbose=True`` でheaderの``schema_hints``をフル版に切り替える(既定は短縮版)。
|
|
203
202
|
"""
|
|
204
203
|
with _write_lock:
|
|
205
204
|
pyfltr.cli.structured_logger.info(_dump(_build_header_record(commands, files, run_id=run_id, verbose=verbose)))
|
|
@@ -258,8 +257,8 @@ def _dump(record: dict[str, typing.Any]) -> str:
|
|
|
258
257
|
|
|
259
258
|
_SCHEMA_HINTS_COMPACT: dict[str, str] = {
|
|
260
259
|
"_note": "non-obvious fields only; -v or get_schema_hints(full=True) for full schema",
|
|
261
|
-
"header.commands_count": "integer count; -v emits the full commands array (also archived)",
|
|
262
260
|
"command.retry_command": "shell to re-run only failing files; failure runs only",
|
|
261
|
+
"command.cached_elapsed": "previous-run elapsed seconds restored with cached=true; this run skipped execution",
|
|
263
262
|
"command.hint-urls": "rule id -> docs URL map; omitted when no URLs resolved",
|
|
264
263
|
"messages[].fix": "safe/unsafe/suggested = auto-fixable; none = no fix; omitted = no info",
|
|
265
264
|
}
|
|
@@ -296,6 +295,10 @@ _SCHEMA_HINTS: dict[str, str] = {
|
|
|
296
295
|
"shell command to re-run only this command on failing files; populated only when the command failed"
|
|
297
296
|
),
|
|
298
297
|
"command.cached": "true = result restored from file-hash cache; rerun with --no-cache to force",
|
|
298
|
+
"command.cached_elapsed": (
|
|
299
|
+
"previous-run elapsed seconds (seconds) restored alongside cached=true; this run skipped execution."
|
|
300
|
+
" elapsed is omitted when cached=true so only this key represents timing"
|
|
301
|
+
),
|
|
299
302
|
"command.truncated": ("diagnostics or message were trimmed; full content is in the archive directory (see header.run_id)"),
|
|
300
303
|
"header.run_id": "ULID identifying this run; use 'pyfltr show-run <run_id>' to fetch full output",
|
|
301
304
|
"warning.hint": (
|
|
@@ -331,11 +334,9 @@ def _build_header_record(
|
|
|
331
334
|
) -> dict[str, typing.Any]:
|
|
332
335
|
"""実行環境の基本情報を header レコード dict として返す。
|
|
333
336
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
``verbose
|
|
337
|
-
フル ``commands`` 配列は実行アーカイブの ``meta.json`` に常時保存されるため、
|
|
338
|
-
短縮時も ``show-run`` 経由で参照できる。
|
|
337
|
+
``commands`` は「実際に実行されるツール集合」(``--only-failed`` や disabled ツール除外後)を
|
|
338
|
+
前提とする。呼び出し側で絞り込み済みの配列を渡すこと。
|
|
339
|
+
``verbose`` は ``schema_hints`` のフル/短縮切替のみに効く。
|
|
339
340
|
"""
|
|
340
341
|
record: dict[str, typing.Any] = {
|
|
341
342
|
"kind": "header",
|
|
@@ -345,11 +346,8 @@ def _build_header_record(
|
|
|
345
346
|
"platform": sys.platform,
|
|
346
347
|
"cwd": os.getcwd(),
|
|
347
348
|
"files": files,
|
|
349
|
+
"commands": commands,
|
|
348
350
|
}
|
|
349
|
-
if verbose:
|
|
350
|
-
record["commands"] = commands
|
|
351
|
-
else:
|
|
352
|
-
record["commands_count"] = len(commands)
|
|
353
351
|
if run_id is not None:
|
|
354
352
|
record["run_id"] = run_id
|
|
355
353
|
# LLM 向けフィールド補足。毎回出力する (header は各 run の先頭 1 行のみ)。
|
|
@@ -408,6 +406,8 @@ def _build_command_record(
|
|
|
408
406
|
メッセージ切り詰めまたは diagnostic 切り詰めが発生した場合は ``truncated`` メタを
|
|
409
407
|
添付する。retry_command は ``CommandResult.retry_command`` が設定されていれば含める。
|
|
410
408
|
``hint_urls`` が非空なら ``hint-urls`` キー(ハイフン区切り)で埋め込む。
|
|
409
|
+
``result.cached`` が真のときは ``elapsed`` ではなく ``cached_elapsed`` キーに
|
|
410
|
+
リネームして出力する(実行をスキップした前回値である旨を LLM に明示するため)。
|
|
411
411
|
"""
|
|
412
412
|
record: dict[str, typing.Any] = {
|
|
413
413
|
"kind": "command",
|
|
@@ -415,9 +415,13 @@ def _build_command_record(
|
|
|
415
415
|
"type": result.command_type,
|
|
416
416
|
"status": result.status,
|
|
417
417
|
"files": result.files,
|
|
418
|
-
"elapsed": round(result.elapsed, 2),
|
|
419
418
|
"diagnostics": diagnostics,
|
|
420
419
|
}
|
|
420
|
+
# cached=True のときは実行をスキップしているため ``elapsed`` は出力せず
|
|
421
|
+
# 前回実行時の計測値を ``cached_elapsed`` として提示する。LLM が「今回の実行時間」と
|
|
422
|
+
# 誤解するのを避けるため両者を同時に出さない設計。
|
|
423
|
+
elapsed_key = "cached_elapsed" if result.cached else "elapsed"
|
|
424
|
+
record[elapsed_key] = round(result.elapsed, 2)
|
|
421
425
|
if result.returncode is not None:
|
|
422
426
|
record["rc"] = result.returncode
|
|
423
427
|
|
|
@@ -137,7 +137,10 @@ def _make_common_parent(custom_commands: collections.abc.Iterable[str] = ()) ->
|
|
|
137
137
|
common.add_argument(
|
|
138
138
|
"--commands",
|
|
139
139
|
default=None,
|
|
140
|
-
|
|
140
|
+
action="append",
|
|
141
|
+
help="対象のコマンド一覧を指定します。複数回指定可能で、各値はカンマ区切りも併用可能です。"
|
|
142
|
+
"例: --commands=mypy --commands=pyright,ruff-check は"
|
|
143
|
+
" --commands=mypy,pyright,ruff-check と同等です。"
|
|
141
144
|
"(既定: ビルトイン + カスタムコマンドを含む、pyproject.toml で有効な全コマンド)",
|
|
142
145
|
)
|
|
143
146
|
common.add_argument("--ui", default=None, action="store_true", help="Textual UI を強制的に有効化します。")
|
|
@@ -358,7 +361,8 @@ def _apply_subcommand_defaults(args: argparse.Namespace) -> None:
|
|
|
358
361
|
if subcommand in ("run", "fast", "run-for-agent"):
|
|
359
362
|
args.exit_zero_even_if_formatted = True
|
|
360
363
|
if subcommand == "fast" and args.commands is None:
|
|
361
|
-
|
|
364
|
+
# ``--commands`` は ``action="append"`` 化によりリストで保持する。
|
|
365
|
+
args.commands = ["fast"]
|
|
362
366
|
if subcommand == "run-for-agent" and args.output_format is None:
|
|
363
367
|
args.output_format = "jsonl"
|
|
364
368
|
|
|
@@ -432,6 +436,26 @@ def run(sys_args: typing.Sequence[str] | None = None) -> int:
|
|
|
432
436
|
os.chdir(original_cwd)
|
|
433
437
|
|
|
434
438
|
|
|
439
|
+
def _flatten_commands_arg(values: list[str] | None, config: pyfltr.config.Config) -> list[str]:
|
|
440
|
+
"""``--commands`` で渡されたリスト(複数回指定の集合)をコマンド名配列に展開する。
|
|
441
|
+
|
|
442
|
+
各要素にはカンマ区切りで複数のコマンドを含められるため、split した上で
|
|
443
|
+
先頭出現を優先した重複除去を行う。``None`` の場合は設定上の全登録コマンド
|
|
444
|
+
(ビルトイン + custom-commands)を返す。
|
|
445
|
+
"""
|
|
446
|
+
if values is None:
|
|
447
|
+
return list(config.command_names)
|
|
448
|
+
seen: set[str] = set()
|
|
449
|
+
result: list[str] = []
|
|
450
|
+
for raw in values:
|
|
451
|
+
for name in raw.split(","):
|
|
452
|
+
if name == "" or name in seen:
|
|
453
|
+
continue
|
|
454
|
+
seen.add(name)
|
|
455
|
+
result.append(name)
|
|
456
|
+
return result
|
|
457
|
+
|
|
458
|
+
|
|
435
459
|
_OUTPUT_FORMAT_ENV = "PYFLTR_OUTPUT_FORMAT"
|
|
436
460
|
_VALID_OUTPUT_FORMATS: frozenset[str] = frozenset(pyfltr.formatters.FORMATTERS.keys())
|
|
437
461
|
|
|
@@ -534,8 +558,9 @@ def _run_impl(
|
|
|
534
558
|
# ビルトインのみの default を返すと custom-commands が常にスキップされる。
|
|
535
559
|
# load_config 後に実体を決定することで、ユーザーが登録した custom-commands
|
|
536
560
|
# (例: svelte-check) も `run` / `ci` サブコマンドのデフォルト動作で走るようにする。
|
|
537
|
-
|
|
538
|
-
|
|
561
|
+
# ``--commands`` は ``action="append"`` によりリストで渡るため、各要素を
|
|
562
|
+
# カンマ区切りで再分割して平坦化する。重複は先出を優先して除去する。
|
|
563
|
+
commands: list[str] = pyfltr.config.resolve_aliases(_flatten_commands_arg(args.commands, config), config)
|
|
539
564
|
for command in commands:
|
|
540
565
|
if command not in config.values:
|
|
541
566
|
parser.error(f"コマンドが見つかりません: {command}")
|
|
@@ -608,6 +633,11 @@ def run_pipeline(
|
|
|
608
633
|
if only_failed_exit_early:
|
|
609
634
|
return 0, None
|
|
610
635
|
|
|
636
|
+
# 実行対象として有効化されていないコマンドはパイプラインから除外する。
|
|
637
|
+
# split_commands_for_execution と同じ条件 (``config.values.get(cmd) is True``) で絞り込み、
|
|
638
|
+
# JSONL header・実行アーカイブ・formatter ctx へ渡す commands を「実際に実行されるもの」に統一する。
|
|
639
|
+
commands = [c for c in commands if config.values.get(c) is True]
|
|
640
|
+
|
|
611
641
|
# retry_command 再構成用のベース情報を確定する。original_cwd は run() が保存した
|
|
612
642
|
# --work-dir 適用前の cwd、original_sys_args は起動時の sys.argv[1:] のコピー。
|
|
613
643
|
effective_cwd = original_cwd if original_cwd is not None else os.getcwd()
|
|
@@ -604,7 +604,7 @@ def test_resolve_bin_commandline_mise_not_installed(mocker) -> None:
|
|
|
604
604
|
|
|
605
605
|
|
|
606
606
|
def test_resolve_bin_commandline_mise_tool_not_installed(mocker) -> None:
|
|
607
|
-
"""miseモードでツールが未インストールの場合、FileNotFoundError
|
|
607
|
+
"""miseモードでツールが未インストールの場合、FileNotFoundErrorをstderr付きで送出する。"""
|
|
608
608
|
mocker.patch("shutil.which", return_value="/usr/local/bin/mise")
|
|
609
609
|
mocker.patch(
|
|
610
610
|
"subprocess.run",
|
|
@@ -619,10 +619,169 @@ def test_resolve_bin_commandline_mise_tool_not_installed(mocker) -> None:
|
|
|
619
619
|
config = pyfltr.config.create_default_config()
|
|
620
620
|
config.values["bin-runner"] = "mise"
|
|
621
621
|
|
|
622
|
-
with pytest.raises(FileNotFoundError, match="
|
|
622
|
+
with pytest.raises(FileNotFoundError, match="tool not found"):
|
|
623
623
|
pyfltr.command._resolve_bin_commandline("ec", config)
|
|
624
624
|
|
|
625
625
|
|
|
626
|
+
def test_resolve_bin_commandline_mise_untrusted_auto_trust_success(mocker) -> None:
|
|
627
|
+
"""未信頼エラー → trust成功 → 再チェック成功の3段で最終的に通常成功扱いになる。"""
|
|
628
|
+
mocker.patch("shutil.which", return_value="/usr/local/bin/mise")
|
|
629
|
+
mock_run = mocker.patch(
|
|
630
|
+
"subprocess.run",
|
|
631
|
+
side_effect=[
|
|
632
|
+
# 1回目の事前チェック: config未信頼で失敗
|
|
633
|
+
subprocess.CompletedProcess(
|
|
634
|
+
["mise", "exec"],
|
|
635
|
+
returncode=1,
|
|
636
|
+
stdout="",
|
|
637
|
+
stderr="mise ERROR Config files in /path/to/mise.toml are not trusted.",
|
|
638
|
+
),
|
|
639
|
+
# mise trust --yes --all: 成功
|
|
640
|
+
subprocess.CompletedProcess(
|
|
641
|
+
["mise", "trust", "--yes", "--all"],
|
|
642
|
+
returncode=0,
|
|
643
|
+
stdout="",
|
|
644
|
+
stderr="",
|
|
645
|
+
),
|
|
646
|
+
# 2回目の事前チェック(リトライ): 成功
|
|
647
|
+
subprocess.CompletedProcess(
|
|
648
|
+
["mise", "exec"],
|
|
649
|
+
returncode=0,
|
|
650
|
+
stdout="typos 1.0.0",
|
|
651
|
+
stderr="",
|
|
652
|
+
),
|
|
653
|
+
],
|
|
654
|
+
)
|
|
655
|
+
|
|
656
|
+
config = pyfltr.config.create_default_config()
|
|
657
|
+
config.values["bin-runner"] = "mise"
|
|
658
|
+
config.values["mise-auto-trust"] = True
|
|
659
|
+
|
|
660
|
+
path, prefix = pyfltr.command._resolve_bin_commandline("typos", config)
|
|
661
|
+
|
|
662
|
+
assert path == "mise"
|
|
663
|
+
assert prefix == ["exec", "typos@latest", "--", "typos"]
|
|
664
|
+
# 事前チェック → trust → リトライの3回が実際に発生したことを確認
|
|
665
|
+
assert mock_run.call_count == 3
|
|
666
|
+
|
|
667
|
+
|
|
668
|
+
def test_resolve_bin_commandline_mise_untrusted_auto_trust_disabled(mocker) -> None:
|
|
669
|
+
"""mise-auto-trust=False のとき trust が呼ばれず、stderr含むエラーメッセージで失敗する。"""
|
|
670
|
+
mocker.patch("shutil.which", return_value="/usr/local/bin/mise")
|
|
671
|
+
mock_run = mocker.patch(
|
|
672
|
+
"subprocess.run",
|
|
673
|
+
return_value=subprocess.CompletedProcess(
|
|
674
|
+
["mise", "exec"],
|
|
675
|
+
returncode=1,
|
|
676
|
+
stdout="",
|
|
677
|
+
stderr="mise ERROR Config files in /path/to/mise.toml are not trusted.",
|
|
678
|
+
),
|
|
679
|
+
)
|
|
680
|
+
|
|
681
|
+
config = pyfltr.config.create_default_config()
|
|
682
|
+
config.values["bin-runner"] = "mise"
|
|
683
|
+
config.values["mise-auto-trust"] = False
|
|
684
|
+
|
|
685
|
+
with pytest.raises(FileNotFoundError, match="not trusted"):
|
|
686
|
+
pyfltr.command._resolve_bin_commandline("typos", config)
|
|
687
|
+
|
|
688
|
+
# trust コマンドは呼ばれていないことを確認(subprocess.run の呼び出しは1回のみ)
|
|
689
|
+
assert mock_run.call_count == 1
|
|
690
|
+
|
|
691
|
+
|
|
692
|
+
def test_resolve_bin_commandline_mise_other_error_no_retry(mocker) -> None:
|
|
693
|
+
"""未信頼以外のエラー(plugin not found等)ではtrustを呼ばずそのまま失敗する。"""
|
|
694
|
+
mocker.patch("shutil.which", return_value="/usr/local/bin/mise")
|
|
695
|
+
mock_run = mocker.patch(
|
|
696
|
+
"subprocess.run",
|
|
697
|
+
return_value=subprocess.CompletedProcess(
|
|
698
|
+
["mise", "exec"],
|
|
699
|
+
returncode=1,
|
|
700
|
+
stdout="",
|
|
701
|
+
stderr="mise ERROR plugin not found: typos",
|
|
702
|
+
),
|
|
703
|
+
)
|
|
704
|
+
|
|
705
|
+
config = pyfltr.config.create_default_config()
|
|
706
|
+
config.values["bin-runner"] = "mise"
|
|
707
|
+
config.values["mise-auto-trust"] = True
|
|
708
|
+
|
|
709
|
+
with pytest.raises(FileNotFoundError, match="plugin not found"):
|
|
710
|
+
pyfltr.command._resolve_bin_commandline("typos", config)
|
|
711
|
+
|
|
712
|
+
# trust コマンドは呼ばれていないことを確認(subprocess.run の呼び出しは1回のみ)
|
|
713
|
+
assert mock_run.call_count == 1
|
|
714
|
+
|
|
715
|
+
|
|
716
|
+
def test_resolve_bin_commandline_mise_untrusted_auto_trust_retry_failure(mocker) -> None:
|
|
717
|
+
"""trust後の再チェックも失敗する場合、リトライが1回で打ち切られ通常失敗扱いになる。"""
|
|
718
|
+
mocker.patch("shutil.which", return_value="/usr/local/bin/mise")
|
|
719
|
+
mocker.patch(
|
|
720
|
+
"subprocess.run",
|
|
721
|
+
side_effect=[
|
|
722
|
+
# 1回目の事前チェック: config未信頼で失敗
|
|
723
|
+
subprocess.CompletedProcess(
|
|
724
|
+
["mise", "exec"],
|
|
725
|
+
returncode=1,
|
|
726
|
+
stdout="",
|
|
727
|
+
stderr="mise ERROR Config files in /path/to/mise.toml are not trusted.",
|
|
728
|
+
),
|
|
729
|
+
# mise trust --yes --all: 成功
|
|
730
|
+
subprocess.CompletedProcess(
|
|
731
|
+
["mise", "trust", "--yes", "--all"],
|
|
732
|
+
returncode=0,
|
|
733
|
+
stdout="",
|
|
734
|
+
stderr="",
|
|
735
|
+
),
|
|
736
|
+
# 2回目の事前チェック(リトライ): 再度失敗
|
|
737
|
+
subprocess.CompletedProcess(
|
|
738
|
+
["mise", "exec"],
|
|
739
|
+
returncode=1,
|
|
740
|
+
stdout="",
|
|
741
|
+
stderr="mise ERROR some other failure after trust",
|
|
742
|
+
),
|
|
743
|
+
],
|
|
744
|
+
)
|
|
745
|
+
|
|
746
|
+
config = pyfltr.config.create_default_config()
|
|
747
|
+
config.values["bin-runner"] = "mise"
|
|
748
|
+
config.values["mise-auto-trust"] = True
|
|
749
|
+
|
|
750
|
+
with pytest.raises(FileNotFoundError, match="some other failure after trust"):
|
|
751
|
+
pyfltr.command._resolve_bin_commandline("typos", config)
|
|
752
|
+
|
|
753
|
+
|
|
754
|
+
def test_resolve_bin_commandline_mise_untrusted_auto_trust_trust_failure(mocker) -> None:
|
|
755
|
+
"""mise trust コマンド自体が失敗した場合、trust.stderr を含むエラーで即座に失敗する。"""
|
|
756
|
+
mocker.patch("shutil.which", return_value="/usr/local/bin/mise")
|
|
757
|
+
mocker.patch(
|
|
758
|
+
"subprocess.run",
|
|
759
|
+
side_effect=[
|
|
760
|
+
# 事前チェック: config未信頼で失敗
|
|
761
|
+
subprocess.CompletedProcess(
|
|
762
|
+
["mise", "exec"],
|
|
763
|
+
returncode=1,
|
|
764
|
+
stdout="",
|
|
765
|
+
stderr="mise ERROR Config files in /path/to/mise.toml are not trusted.",
|
|
766
|
+
),
|
|
767
|
+
# mise trust --yes --all: 失敗(権限不足等)
|
|
768
|
+
subprocess.CompletedProcess(
|
|
769
|
+
["mise", "trust", "--yes", "--all"],
|
|
770
|
+
returncode=1,
|
|
771
|
+
stdout="",
|
|
772
|
+
stderr="mise ERROR permission denied: /path/to/mise.toml",
|
|
773
|
+
),
|
|
774
|
+
],
|
|
775
|
+
)
|
|
776
|
+
|
|
777
|
+
config = pyfltr.config.create_default_config()
|
|
778
|
+
config.values["bin-runner"] = "mise"
|
|
779
|
+
config.values["mise-auto-trust"] = True
|
|
780
|
+
|
|
781
|
+
with pytest.raises(FileNotFoundError, match="permission denied"):
|
|
782
|
+
pyfltr.command._resolve_bin_commandline("typos", config)
|
|
783
|
+
|
|
784
|
+
|
|
626
785
|
def test_failed_resolution_result() -> None:
|
|
627
786
|
"""_failed_resolution_resultが失敗用のCommandResultを返す。"""
|
|
628
787
|
command_info = pyfltr.config.CommandInfo(type="linter")
|
|
@@ -852,6 +852,26 @@ bin-runner = "bogus"
|
|
|
852
852
|
pyfltr.config.load_config(config_dir=tmp_path)
|
|
853
853
|
|
|
854
854
|
|
|
855
|
+
def test_mise_auto_trust_default() -> None:
|
|
856
|
+
"""mise-auto-trust の既定値は True。"""
|
|
857
|
+
config = pyfltr.config.create_default_config()
|
|
858
|
+
assert config["mise-auto-trust"] is True
|
|
859
|
+
|
|
860
|
+
|
|
861
|
+
def test_mise_auto_trust_disable(tmp_path: pathlib.Path) -> None:
|
|
862
|
+
"""pyproject.toml で mise-auto-trust を False に設定できる。"""
|
|
863
|
+
(tmp_path / "pyproject.toml").write_text("[tool.pyfltr]\nmise-auto-trust = false\n")
|
|
864
|
+
config = pyfltr.config.load_config(config_dir=tmp_path)
|
|
865
|
+
assert config["mise-auto-trust"] is False
|
|
866
|
+
|
|
867
|
+
|
|
868
|
+
def test_mise_auto_trust_invalid_type_rejected(tmp_path: pathlib.Path) -> None:
|
|
869
|
+
"""mise-auto-trust に bool 以外の値を指定するとエラーになる。"""
|
|
870
|
+
(tmp_path / "pyproject.toml").write_text('[tool.pyfltr]\nmise-auto-trust = "yes"\n')
|
|
871
|
+
with pytest.raises(ValueError, match="mise-auto-trust"):
|
|
872
|
+
pyfltr.config.load_config(config_dir=tmp_path)
|
|
873
|
+
|
|
874
|
+
|
|
855
875
|
def test_preset_latest_suppresses_language_categories(tmp_path: pathlib.Path) -> None:
|
|
856
876
|
"""preset = "latest" 単独 (カテゴリキー全 False) では全言語のツールが False に押し戻される。"""
|
|
857
877
|
(tmp_path / "pyproject.toml").write_text('[tool.pyfltr]\npreset = "latest"\n')
|