grift-cli 0.5.2__tar.gz → 0.5.3__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.
- {grift_cli-0.5.2 → grift_cli-0.5.3}/CHANGELOG.md +14 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/PKG-INFO +3 -3
- {grift_cli-0.5.2 → grift_cli-0.5.3}/README.en.md +1 -1
- {grift_cli-0.5.2 → grift_cli-0.5.3}/README.md +2 -2
- {grift_cli-0.5.2 → grift_cli-0.5.3}/action.yml +1 -1
- {grift_cli-0.5.2 → grift_cli-0.5.3}/pyproject.toml +1 -1
- {grift_cli-0.5.2 → grift_cli-0.5.3}/scripts/hygiene_grep.py +4 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_cli/__main__.py +75 -10
- {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/version.py +2 -2
- grift_cli-0.5.3/tests/test_default_report_path.py +114 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_hygiene.py +4 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/.github/workflows/ci.yml +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/.github/workflows/kpi-monthly.yml +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/.github/workflows/publish-testpypi.yml +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/.github/workflows/publish.yml +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/.gitignore +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/LICENSE +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/corpus/AD-PILOT-20260822.md +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/corpus/DISCRIMINANT-v2026.09.md +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/corpus/DISCRIMINANT-v2026.11.md +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/corpus/ad-pilot.json +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/corpus/manifest.toml +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/corpus/pins-v2026.09.toml +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/corpus/pins-v2026.11.toml +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/corpus/v2026.09/distributions.json +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/corpus/v2026.11/distributions.json +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/docs/corpus-protocol.md +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/docs/coverage-map.md +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/docs/export-schema.md +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/docs/identity-schema.md +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/docs/norms.md +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/docs/persona-answers.md +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/docs/report-schema.md +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/golden/README.md +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/golden/coverage.md +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/golden/expected/G1-click.json +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/golden/expected/G10-scvi-tools.json +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/golden/expected/G11-kilo.json +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/golden/expected/G12-httpx.json +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/golden/expected/G13-voicevox.json +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/golden/expected/G2-gitignore.json +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/golden/expected/G3-spoon-knife.json +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/golden/expected/G4-express.json +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/golden/expected/G5-typer.json +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/golden/expected/G6-claude-code.json +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/golden/expected/G7-axios.json +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/golden/expected/G8-co.json +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/golden/expected/G9-pyscript.json +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/golden/identity/G1-click.toml +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/golden/identity/example.toml +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/golden/pins.toml +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/scripts/admission_v2026_11.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/scripts/build_dist_v2026_11.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/scripts/build_distributions.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/scripts/check_forbidden_vocab.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/scripts/corpus_ad_pilot.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/scripts/corpus_run.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/scripts/discriminant_v2026.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/scripts/discriminant_v2026_11.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/scripts/gen_coverage_table.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/scripts/gen_golden_expected.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_cli/__init__.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/__init__.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/activity.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/analyze.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/cochange.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/context_profile.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/contribute.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/core_period.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/data/v2026.09/distributions.json +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/data/v2026.11/distributions.json +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/export.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/gitutil.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/identity.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/lineage.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/observation.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/origin.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/paths.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/reference.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/report.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/rework.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/schema.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/scope.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/survival.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/tests_observed.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/verify.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/conftest.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/coverage_matrix.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/git_fixture.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_activity.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_cli.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_cochange.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_context_profile.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_contribute.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_coverage.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_discriminant_claims.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_export.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_export_recipe.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_forbidden_vocab.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_gitutil.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_golden.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_h5_swarm.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_identity_validation.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_lifecycle_v2.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_not_observed.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_origin.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_persona_answers.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_release_gate.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_report.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_rework.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_schema.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_scope.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_shared_block.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_survival.py +0 -0
- {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_verify.py +0 -0
|
@@ -4,6 +4,20 @@
|
|
|
4
4
|
|
|
5
5
|
タグ・PyPI・リポ public 化は本ファイルの記載対象外(人間ゲート)。
|
|
6
6
|
|
|
7
|
+
## [0.5.3] — 2026-08-23
|
|
8
|
+
|
|
9
|
+
UX 改善(代表フィードバック)+ 公開 README の整合。
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- **`grift report`(引数なし)= そのディレクトリを分析して `./out/report.{json,md}` を自動作成**(`out/` がなければ作る)。引数を渡した場合は従来どおり既存 JSON からの再レンダリング(再分析なし)
|
|
14
|
+
- `grift contribute`(引数なし)は `./out/report.json` → `.grift-out/report.json` → `./report.json` を自動探索。無ければ「先に `grift report` を」と案内
|
|
15
|
+
- GitHub Action の使用例を `@v0.5.2` ぼ更新・「本公開は別ゲート」注記を公開済み表示に更新(README 日英)
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- hygiene 除外リストに内部調査文書プレフィックス(SMOKE / REREVIEW / RELEASE-REHEARSAL / INTERNAL-PILOT)を追加
|
|
20
|
+
|
|
7
21
|
## [0.5.2] — 2026-08-23
|
|
8
22
|
|
|
9
23
|
基準の憲法(norms / reader's guide / verify)+ 文脈層(context_profile v2・lifecycle-v2)+ corpus v2026.11 + contribute。
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: grift-cli
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.3
|
|
4
4
|
Summary: Deterministic TEP evidence metrics from a single git repository. No LLM.
|
|
5
5
|
Project-URL: Homepage, https://github.com/Cor-Incorporated/grift-cli
|
|
6
6
|
Author: TEP contributors
|
|
@@ -107,7 +107,7 @@ v2026.09 の記録(Run 2: A vs C `separated` ほか)は `corpus/DISCRIMINANT
|
|
|
107
107
|
## GitHub Action(観測のみ)
|
|
108
108
|
|
|
109
109
|
```yaml
|
|
110
|
-
uses: Cor-Incorporated/grift-cli@v0.5.
|
|
110
|
+
uses: Cor-Incorporated/grift-cli@v0.5.3
|
|
111
111
|
with:
|
|
112
112
|
scope: repo
|
|
113
113
|
```
|
|
@@ -128,7 +128,7 @@ with:
|
|
|
128
128
|
|
|
129
129
|
- 公開リポ: https://github.com/Cor-Incorporated/grift-cli
|
|
130
130
|
- コマンド名: **`grift`**(方法論名 TEP はレポートに残す)
|
|
131
|
-
- PyPI: 配布名 **`grift-cli
|
|
131
|
+
- PyPI: 配布名 **`grift-cli`**(最新 0.5.2 を公開済み: `pipx install grift-cli`)
|
|
132
132
|
|
|
133
133
|
## License
|
|
134
134
|
|
|
@@ -84,7 +84,7 @@ v2026.09 の記録(Run 2: A vs C `separated` ほか)は `corpus/DISCRIMINANT
|
|
|
84
84
|
## GitHub Action(観測のみ)
|
|
85
85
|
|
|
86
86
|
```yaml
|
|
87
|
-
uses: Cor-Incorporated/grift-cli@v0.5.
|
|
87
|
+
uses: Cor-Incorporated/grift-cli@v0.5.3
|
|
88
88
|
with:
|
|
89
89
|
scope: repo
|
|
90
90
|
```
|
|
@@ -105,7 +105,7 @@ with:
|
|
|
105
105
|
|
|
106
106
|
- 公開リポ: https://github.com/Cor-Incorporated/grift-cli
|
|
107
107
|
- コマンド名: **`grift`**(方法論名 TEP はレポートに残す)
|
|
108
|
-
- PyPI: 配布名 **`grift-cli
|
|
108
|
+
- PyPI: 配布名 **`grift-cli`**(最新 0.5.2 を公開済み: `pipx install grift-cli`)
|
|
109
109
|
|
|
110
110
|
## License
|
|
111
111
|
|
|
@@ -16,10 +16,11 @@ from tep_core.verify import CANNOT_VERIFY, MISMATCH, VERIFIED, verify_report
|
|
|
16
16
|
from tep_core.version import __version__
|
|
17
17
|
|
|
18
18
|
_EPILOG = """examples:
|
|
19
|
-
grift analyze
|
|
20
|
-
grift
|
|
19
|
+
grift report # analyze the current repo → ./out/report.{json,md}
|
|
20
|
+
grift report path/report.json # re-render md from an existing report (no re-analysis)
|
|
21
|
+
grift analyze . --scope repo --out ./out
|
|
21
22
|
grift verify ./out/report.json --repo ./repo
|
|
22
|
-
grift contribute ./out/report.json
|
|
23
|
+
grift contribute # build opt-in payload from ./out/report.json (never sends)
|
|
23
24
|
詳細: README"""
|
|
24
25
|
|
|
25
26
|
|
|
@@ -141,11 +142,17 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
141
142
|
|
|
142
143
|
render = sub.add_parser(
|
|
143
144
|
"report",
|
|
144
|
-
help="
|
|
145
|
+
help="Analyze the current repo and write ./out/report.{json,md}; or re-render md from an existing report.json",
|
|
145
146
|
epilog=_EPILOG,
|
|
146
147
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
147
148
|
)
|
|
148
|
-
render.add_argument(
|
|
149
|
+
render.add_argument(
|
|
150
|
+
"report_json",
|
|
151
|
+
type=Path,
|
|
152
|
+
nargs="?",
|
|
153
|
+
default=None,
|
|
154
|
+
help="Path to an existing report.json to re-render (default: analyze the current repo into ./out)",
|
|
155
|
+
)
|
|
149
156
|
render.add_argument(
|
|
150
157
|
"--out",
|
|
151
158
|
type=Path,
|
|
@@ -159,7 +166,13 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
159
166
|
epilog=_EPILOG,
|
|
160
167
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
161
168
|
)
|
|
162
|
-
contribute.add_argument(
|
|
169
|
+
contribute.add_argument(
|
|
170
|
+
"report_json",
|
|
171
|
+
type=Path,
|
|
172
|
+
nargs="?",
|
|
173
|
+
default=None,
|
|
174
|
+
help="Path to a repo-scope report.json (default: search ./out, .grift-out, ./)",
|
|
175
|
+
)
|
|
163
176
|
contribute.add_argument(
|
|
164
177
|
"--out",
|
|
165
178
|
type=Path,
|
|
@@ -243,11 +256,33 @@ def _run_verify(args: argparse.Namespace) -> int:
|
|
|
243
256
|
return 2
|
|
244
257
|
|
|
245
258
|
|
|
259
|
+
_DEFAULT_REPORT_SEARCH = (
|
|
260
|
+
Path("out") / "report.json",
|
|
261
|
+
Path(".grift-out") / "report.json",
|
|
262
|
+
Path("report.json"),
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def _resolve_report_path(explicit: Path | None) -> tuple[Path | None, str]:
|
|
267
|
+
"""Return (path, guidance). Search ./out, .grift-out, ./ when no explicit path."""
|
|
268
|
+
if explicit is not None:
|
|
269
|
+
return explicit, ""
|
|
270
|
+
for candidate in _DEFAULT_REPORT_SEARCH:
|
|
271
|
+
if candidate.is_file():
|
|
272
|
+
return candidate, ""
|
|
273
|
+
return None, ""
|
|
274
|
+
|
|
275
|
+
|
|
246
276
|
def _run_report(args: argparse.Namespace) -> int:
|
|
277
|
+
report_path, _guidance = _resolve_report_path(args.report_json)
|
|
278
|
+
if report_path is None:
|
|
279
|
+
# UX (代表 2026-08-23): bare `grift report` in a repo with no prior
|
|
280
|
+
# output = run the analysis now and write ./out/report.{json,md}.
|
|
281
|
+
return _analyze_to_out(scope="repo")
|
|
247
282
|
try:
|
|
248
|
-
payload = json.loads(
|
|
283
|
+
payload = json.loads(report_path.read_text(encoding="utf-8"))
|
|
249
284
|
except (OSError, json.JSONDecodeError) as exc:
|
|
250
|
-
sys.stderr.write(f"report unreadable: {exc}\n")
|
|
285
|
+
sys.stderr.write(f"report unreadable ({report_path}): {exc}\n")
|
|
251
286
|
return 2
|
|
252
287
|
try:
|
|
253
288
|
markdown = render_markdown(payload)
|
|
@@ -263,13 +298,43 @@ def _run_report(args: argparse.Namespace) -> int:
|
|
|
263
298
|
return 0
|
|
264
299
|
|
|
265
300
|
|
|
301
|
+
def _analyze_to_out(*, scope: str = "repo") -> int:
|
|
302
|
+
"""Run the analysis in the current directory and write ./out/report.{json,md}.
|
|
303
|
+
|
|
304
|
+
UX (代表 2026-08-23): bare `grift report` should just produce the reports —
|
|
305
|
+
create ./out if missing. Reuses the analyze pipeline on '.'.
|
|
306
|
+
"""
|
|
307
|
+
repo = Path(".")
|
|
308
|
+
if not (repo / ".git").exists():
|
|
309
|
+
sys.stderr.write("grift: not a git repository (run inside the repo you want to analyze)\n")
|
|
310
|
+
return 2
|
|
311
|
+
identity = discover_identity(repo, None)
|
|
312
|
+
report = analyze_repository(repo, identity, Lineage(), scope=scope)
|
|
313
|
+
markdown = render_markdown(report)
|
|
314
|
+
encoded = json.dumps(report, indent=2, ensure_ascii=False) + "\n"
|
|
315
|
+
out_dir = Path("out")
|
|
316
|
+
out_dir.mkdir(parents=True, exist_ok=True)
|
|
317
|
+
(out_dir / "report.json").write_text(encoded, encoding="utf-8")
|
|
318
|
+
(out_dir / "report.md").write_text(markdown, encoding="utf-8")
|
|
319
|
+
sys.stdout.write(markdown)
|
|
320
|
+
sys.stderr.write(f"\nwrote {out_dir / 'report.json'} and {out_dir / 'report.md'}\n")
|
|
321
|
+
return 0
|
|
322
|
+
|
|
323
|
+
|
|
266
324
|
def _run_contribute(args: argparse.Namespace) -> int:
|
|
267
325
|
from tep_core.contribute import CONFIRMATION_TEXT, build_contribution, render_confirmation
|
|
268
326
|
|
|
327
|
+
report_path, _guidance = _resolve_report_path(args.report_json)
|
|
328
|
+
if report_path is None:
|
|
329
|
+
sys.stderr.write(
|
|
330
|
+
"contribute: no report.json found (searched ./out/report.json, .grift-out/report.json, ./report.json). "
|
|
331
|
+
"Run `grift report` first — it will analyze the repo and write ./out/report.json.\n"
|
|
332
|
+
)
|
|
333
|
+
return 2
|
|
269
334
|
try:
|
|
270
|
-
report = json.loads(
|
|
335
|
+
report = json.loads(report_path.read_text(encoding="utf-8"))
|
|
271
336
|
except (OSError, json.JSONDecodeError) as exc:
|
|
272
|
-
sys.stderr.write(f"report unreadable: {exc}\n")
|
|
337
|
+
sys.stderr.write(f"report unreadable ({report_path}): {exc}\n")
|
|
273
338
|
return 2
|
|
274
339
|
try:
|
|
275
340
|
payload = build_contribution(report)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
__version__ = "0.5.
|
|
1
|
+
__version__ = "0.5.3"
|
|
2
2
|
REPORT_SCHEMA_VERSION = "report-v1"
|
|
3
|
-
DEFINITION_VERSION = "tep-v0.5.
|
|
3
|
+
DEFINITION_VERSION = "tep-v0.5.3-2026-08-23"
|
|
4
4
|
ORIGIN_DEFINITION_VERSION = "origin-v1.1-2026-08-22"
|
|
5
5
|
ACTIVITY_DEFINITION_VERSION = "activity-v1-2026-08-16"
|
|
6
6
|
CORE_ACTIVITY_DEFINITION_VERSION = "core-activity-v1-2026-08-16"
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"""Bare `grift report` / `grift contribute`: default-path search + guidance.
|
|
2
|
+
|
|
3
|
+
代表 UX feedback (2026-08-23): invoking the subcommands without a path used
|
|
4
|
+
to hard-error on argparse / file-not-found without telling the user what to
|
|
5
|
+
do first. Now they search ./out, .grift-out, ./ and, when nothing is found,
|
|
6
|
+
exit 2 with actionable guidance.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import json
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
from tep_cli.__main__ import main
|
|
15
|
+
|
|
16
|
+
from git_fixture import commit, init_repo
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _make_report_json(dir_path: Path) -> Path:
|
|
20
|
+
from tep_core.analyze import analyze_repository
|
|
21
|
+
from tep_core.identity import empty_identity
|
|
22
|
+
from tep_core.lineage import Lineage
|
|
23
|
+
|
|
24
|
+
repo = init_repo(dir_path / "repo")
|
|
25
|
+
(repo / "pyproject.toml").write_text(
|
|
26
|
+
'[project]\nname = "demo"\ndependencies = ["pytest"]\n', encoding="utf-8"
|
|
27
|
+
)
|
|
28
|
+
for index in range(12):
|
|
29
|
+
commit(
|
|
30
|
+
repo,
|
|
31
|
+
email="a@example.com",
|
|
32
|
+
date="2026-01-05",
|
|
33
|
+
message=f"feat: {index}",
|
|
34
|
+
filename="app.py",
|
|
35
|
+
)
|
|
36
|
+
report = analyze_repository(repo, empty_identity(), Lineage(), scope="repo")
|
|
37
|
+
target = dir_path / "out" / "report.json"
|
|
38
|
+
target.parent.mkdir(parents=True, exist_ok=True)
|
|
39
|
+
target.write_text(json.dumps(report, ensure_ascii=False), encoding="utf-8")
|
|
40
|
+
return target
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def test_report_bare_uses_out_default(tmp_path: Path, capsys: object, monkeypatch: object) -> None:
|
|
44
|
+
_make_report_json(tmp_path)
|
|
45
|
+
monkeypatch.chdir(tmp_path)
|
|
46
|
+
code = main(["report"])
|
|
47
|
+
assert code == 0
|
|
48
|
+
out = capsys.readouterr().out
|
|
49
|
+
assert "# TEP analysis" in out
|
|
50
|
+
assert "## Shared block" in out
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def test_report_bare_searches_grift_out(
|
|
54
|
+
tmp_path: Path, capsys: object, monkeypatch: object
|
|
55
|
+
) -> None:
|
|
56
|
+
_make_report_json(tmp_path)
|
|
57
|
+
(tmp_path / ".grift-out").mkdir(exist_ok=True)
|
|
58
|
+
(tmp_path / ".grift-out" / "report.json").write_text(
|
|
59
|
+
(tmp_path / "out" / "report.json").read_text(encoding="utf-8"), encoding="utf-8"
|
|
60
|
+
)
|
|
61
|
+
monkeypatch.chdir(tmp_path / ".grift-out")
|
|
62
|
+
code = main(["report"])
|
|
63
|
+
assert code == 0
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def test_report_bare_without_prior_output_analyzes_cwd(
|
|
67
|
+
tmp_path: Path, capsys: object, monkeypatch: object
|
|
68
|
+
) -> None:
|
|
69
|
+
"""UX: bare `grift report` in a git repo with no ./out → analyze now and
|
|
70
|
+
write ./out/report.{json,md}."""
|
|
71
|
+
from git_fixture import commit as _commit, init_repo as _init
|
|
72
|
+
|
|
73
|
+
repo = _init(tmp_path / "repo")
|
|
74
|
+
for index in range(3):
|
|
75
|
+
_commit(repo, email="a@example.com", date="2026-01-05", message=f"feat: {index}")
|
|
76
|
+
monkeypatch.chdir(repo)
|
|
77
|
+
code = main(["report"])
|
|
78
|
+
assert code == 0
|
|
79
|
+
out = capsys.readouterr()
|
|
80
|
+
assert "## Shared block" in out.out
|
|
81
|
+
assert (repo / "out" / "report.json").is_file()
|
|
82
|
+
assert (repo / "out" / "report.md").is_file()
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def test_report_bare_outside_git_repo_refused(
|
|
86
|
+
tmp_path: Path, capsys: object, monkeypatch: object
|
|
87
|
+
) -> None:
|
|
88
|
+
monkeypatch.chdir(tmp_path)
|
|
89
|
+
code = main(["report"])
|
|
90
|
+
assert code == 2
|
|
91
|
+
assert "not a git repository" in capsys.readouterr().err
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def test_contribute_bare_without_report_gives_guidance(
|
|
95
|
+
tmp_path: Path, capsys: object, monkeypatch: object
|
|
96
|
+
) -> None:
|
|
97
|
+
monkeypatch.chdir(tmp_path)
|
|
98
|
+
code = main(["contribute"])
|
|
99
|
+
assert code == 2
|
|
100
|
+
err = capsys.readouterr().err
|
|
101
|
+
assert "grift report" in err # guidance points to the one-step entry
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def test_contribute_bare_uses_out_default(
|
|
105
|
+
tmp_path: Path, capsys: object, monkeypatch: object
|
|
106
|
+
) -> None:
|
|
107
|
+
# repo-scope report in ./out → bare contribute reaches the F-C1 gate
|
|
108
|
+
_make_report_json(tmp_path)
|
|
109
|
+
monkeypatch.chdir(tmp_path)
|
|
110
|
+
code = main(["contribute", "--out", str(tmp_path / "c.json")]) # non-TTY, no --yes
|
|
111
|
+
assert code == 2 # F-C1 refusal path (not path-resolution error)
|
|
112
|
+
err = capsys.readouterr().err
|
|
113
|
+
assert "公開リポジトリに載ります" in err
|
|
114
|
+
assert "grift analyze . --out ./out" not in err # found the file; failed on consent instead
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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
|