papycli 0.15.2__tar.gz → 0.16.0__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.
- papycli-0.16.0/.github/workflows/copilot-review.yml +43 -0
- papycli-0.16.0/.release-please-manifest.json +3 -0
- {papycli-0.15.2 → papycli-0.16.0}/CHANGELOG.md +23 -0
- {papycli-0.15.2 → papycli-0.16.0}/PKG-INFO +11 -5
- {papycli-0.15.2 → papycli-0.16.0}/README.ja.md +9 -4
- {papycli-0.15.2 → papycli-0.16.0}/README.md +9 -4
- papycli-0.16.0/docs/superpowers/plans/2026-04-01-config-add-upgrade.md +354 -0
- papycli-0.16.0/docs/superpowers/plans/2026-04-02-dotenv-autoload.md +263 -0
- papycli-0.16.0/docs/superpowers/specs/2026-04-01-config-add-upgrade-design.md +66 -0
- papycli-0.16.0/docs/superpowers/specs/2026-04-02-dotenv-autoload-design.md +74 -0
- {papycli-0.15.2 → papycli-0.16.0}/pyproject.toml +3 -2
- {papycli-0.15.2 → papycli-0.16.0}/src/papycli/config.py +19 -4
- {papycli-0.15.2 → papycli-0.16.0}/src/papycli/main.py +74 -5
- {papycli-0.15.2 → papycli-0.16.0}/tests/unittest/test_main.py +227 -1
- {papycli-0.15.2 → papycli-0.16.0}/uv.lock +229 -1
- papycli-0.15.2/.github/workflows/copilot-review.yml +0 -69
- papycli-0.15.2/.release-please-manifest.json +0 -3
- {papycli-0.15.2 → papycli-0.16.0}/.github/copilot-instructions.md +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/.github/workflows/docs.yml +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/.github/workflows/release-please.yml +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/.gitignore +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/.pre-commit-config.yaml +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/.python-version +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/CLAUDE.md +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/LICENSE +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/design/2026-03-27-completion-static-script.md +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/design/2026-03-28-claude-md-simplification-plan.md +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/design/2026-03-28-claude-md-simplification.md +0 -0
- {papycli-0.15.2 → papycli-0.16.0/docs}/design_doc.md +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/docs/development.md +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/docs/index.md +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/docs/installation.md +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/docs/ja/development.md +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/docs/ja/index.md +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/docs/ja/installation.md +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/docs/ja/plugins.md +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/docs/ja/quickstart.md +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/docs/ja/reference.md +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/docs/plugins.md +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/docs/quickstart.md +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/docs/reference.md +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/examples/petstore/docker-compose.yml +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/examples/petstore/petstore-oas3.json +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/examples/request_filter/README.md +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/examples/request_filter/pyproject.toml +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/examples/request_filter/src/papycli_debug_filter/__init__.py +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/examples/response_filter/README.md +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/examples/response_filter/pyproject.toml +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/examples/response_filter/src/papycli_debug_response_filter/__init__.py +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/mkdocs.yml +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/release-please-config.json +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/src/papycli/__init__.py +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/src/papycli/api_call.py +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/src/papycli/checker.py +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/src/papycli/completion.py +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/src/papycli/filters.py +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/src/papycli/i18n.py +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/src/papycli/init_cmd.py +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/src/papycli/response_checker.py +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/src/papycli/spec_loader.py +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/src/papycli/summary.py +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/tests/integration/__init__.py +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/tests/integration/conftest.py +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/tests/integration/test_integration.py +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/tests/unittest/conftest.py +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/tests/unittest/test_api_call.py +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/tests/unittest/test_checker.py +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/tests/unittest/test_completion.py +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/tests/unittest/test_config.py +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/tests/unittest/test_filters.py +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/tests/unittest/test_i18n.py +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/tests/unittest/test_init_cmd.py +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/tests/unittest/test_response_checker.py +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/tests/unittest/test_spec_loader.py +0 -0
- {papycli-0.15.2 → papycli-0.16.0}/tests/unittest/test_summary.py +0 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
name: Copilot Review
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
types:
|
|
6
|
+
# opened は除外する。PR 作成時はリポジトリ設定により Copilot レビューが
|
|
7
|
+
# 自動実行されるため、ここでリクエストすると二重実行になる。
|
|
8
|
+
- synchronize
|
|
9
|
+
|
|
10
|
+
# このワークフローを動作させるには、以下の設定が必要:
|
|
11
|
+
# 1. Copilot コードレビューがリポジトリで有効になっていること
|
|
12
|
+
# (Settings → Copilot → Code review)
|
|
13
|
+
# 2. Copilot が有効なユーザーの Personal Access Token (classic, repo スコープ) を
|
|
14
|
+
# リポジトリシークレット GH_PAT に設定すること
|
|
15
|
+
# (GITHUB_TOKEN は Copilot 権限を持たないため動作しない)
|
|
16
|
+
permissions: {}
|
|
17
|
+
|
|
18
|
+
# 同一 PR への連続プッシュで多重実行されないよう PR 番号単位で直列化する。
|
|
19
|
+
# cancel-in-progress: true にすることで古い実行をキャンセルし最新のみを実行する。
|
|
20
|
+
concurrency:
|
|
21
|
+
group: copilot-review-${{ github.event.pull_request.number }}
|
|
22
|
+
cancel-in-progress: true
|
|
23
|
+
|
|
24
|
+
jobs:
|
|
25
|
+
request-copilot-review:
|
|
26
|
+
name: Request Copilot review
|
|
27
|
+
runs-on: ubuntu-latest
|
|
28
|
+
# fork からの PR ではシークレットが利用できないためスキップする。
|
|
29
|
+
if: github.event.pull_request.head.repo.full_name == github.repository
|
|
30
|
+
steps:
|
|
31
|
+
- name: Checkout repository
|
|
32
|
+
uses: actions/checkout@v4
|
|
33
|
+
with:
|
|
34
|
+
fetch-depth: 1
|
|
35
|
+
|
|
36
|
+
- name: Request review from Copilot
|
|
37
|
+
env:
|
|
38
|
+
GH_TOKEN: ${{ secrets.GH_PAT }}
|
|
39
|
+
run: |
|
|
40
|
+
# すでにレビューリクエスト済みの場合は一度削除してから再リクエストする。
|
|
41
|
+
# 削除→再追加することで、新しいコミットがプッシュされたときも Copilot が再レビューを行う。
|
|
42
|
+
gh pr edit ${{ github.event.pull_request.number }} --remove-reviewer @copilot 2>/dev/null || true
|
|
43
|
+
gh pr edit ${{ github.event.pull_request.number }} --add-reviewer @copilot
|
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.16.0](https://github.com/tmonj1/papycli/compare/v0.15.2...v0.16.0) (2026-04-02)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* .env ファイルの自動読み込み ([#167](https://github.com/tmonj1/papycli/issues/167)) ([950f9a9](https://github.com/tmonj1/papycli/commit/950f9a9c2af862e2d1e8545d3ae9b922a4b8c62a))
|
|
9
|
+
* config add に --upgrade オプションを追加する ([#162](https://github.com/tmonj1/papycli/issues/162)) ([cec6586](https://github.com/tmonj1/papycli/commit/cec6586ca5be6b0c21038c606b7ead2bdd641077))
|
|
10
|
+
* implement config add upgrade option ([0e3134f](https://github.com/tmonj1/papycli/commit/0e3134f4e6d6761e5c6aa38a6985c744e47b869e))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* **ci:** add actions/checkout step before gh CLI calls in copilot-review workflow ([ae6aaa3](https://github.com/tmonj1/papycli/commit/ae6aaa3874cb405301fd799d9f32c86a08c6bb9f))
|
|
16
|
+
* **ci:** add checkout step to copilot-review workflow ([#166](https://github.com/tmonj1/papycli/issues/166)) ([ae6aaa3](https://github.com/tmonj1/papycli/commit/ae6aaa3874cb405301fd799d9f32c86a08c6bb9f))
|
|
17
|
+
* **ci:** replace direct API calls with gh pr edit --add-reviewer [@copilot](https://github.com/copilot) ([2ba29d9](https://github.com/tmonj1/papycli/commit/2ba29d92319496ab0a9bc4998fb0f86ea501e9ed))
|
|
18
|
+
* **ci:** trigger Copilot re-review on push via gh pr edit --add-reviewer [@copilot](https://github.com/copilot) ([#164](https://github.com/tmonj1/papycli/issues/164)) ([2ba29d9](https://github.com/tmonj1/papycli/commit/2ba29d92319496ab0a9bc4998fb0f86ea501e9ed))
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
### Documentation
|
|
22
|
+
|
|
23
|
+
* add design spec for config add --upgrade option ([b55938e](https://github.com/tmonj1/papycli/commit/b55938eb98c16aa482858d96c5dce689b138f6e8))
|
|
24
|
+
* add implementation plan for config add --upgrade option ([8af1594](https://github.com/tmonj1/papycli/commit/8af15946b1ea65e3bed4b21da8de8649a1bd292e))
|
|
25
|
+
|
|
3
26
|
## [0.15.2](https://github.com/tmonj1/papycli/compare/v0.15.1...v0.15.2) (2026-04-01)
|
|
4
27
|
|
|
5
28
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: papycli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.16.0
|
|
4
4
|
Summary: A CLI tool to call REST APIs defined in OpenAPI 3.0 specs
|
|
5
5
|
Project-URL: Homepage, https://github.com/tmonj1/papycli
|
|
6
6
|
Project-URL: Repository, https://github.com/tmonj1/papycli
|
|
@@ -21,6 +21,7 @@ Classifier: Topic :: Internet :: WWW/HTTP
|
|
|
21
21
|
Classifier: Topic :: Utilities
|
|
22
22
|
Requires-Python: >=3.12
|
|
23
23
|
Requires-Dist: click>=8.1
|
|
24
|
+
Requires-Dist: python-dotenv>=1.0
|
|
24
25
|
Requires-Dist: pyyaml>=6.0
|
|
25
26
|
Requires-Dist: requests>=2.32
|
|
26
27
|
Requires-Dist: rich>=13.0
|
|
@@ -281,10 +282,15 @@ Options:
|
|
|
281
282
|
--help / -h Show help
|
|
282
283
|
|
|
283
284
|
Environment variables:
|
|
284
|
-
PAPYCLI_CONF_DIR
|
|
285
|
-
PAPYCLI_CUSTOM_HEADER
|
|
286
|
-
|
|
287
|
-
|
|
285
|
+
PAPYCLI_CONF_DIR Path to the config directory (default: ~/.papycli)
|
|
286
|
+
PAPYCLI_CUSTOM_HEADER Custom HTTP headers applied to every request.
|
|
287
|
+
Separate multiple headers with newlines:
|
|
288
|
+
export PAPYCLI_CUSTOM_HEADER=$'Authorization: Bearer token\nX-Tenant: acme'
|
|
289
|
+
PAPYCLI_DISABLE_DOTENV Set to 1 to disable automatic .env file loading.
|
|
290
|
+
By default papycli loads .env from the current directory
|
|
291
|
+
and $PAPYCLI_CONF_DIR on startup. Disable this when running
|
|
292
|
+
in untrusted directories to prevent unintended env injection:
|
|
293
|
+
export PAPYCLI_DISABLE_DOTENV=1
|
|
288
294
|
```
|
|
289
295
|
|
|
290
296
|
---
|
|
@@ -252,10 +252,15 @@ papycli <method> <resource> [options]
|
|
|
252
252
|
--help / -h 使い方を表示する
|
|
253
253
|
|
|
254
254
|
環境変数:
|
|
255
|
-
PAPYCLI_CONF_DIR
|
|
256
|
-
PAPYCLI_CUSTOM_HEADER
|
|
257
|
-
|
|
258
|
-
|
|
255
|
+
PAPYCLI_CONF_DIR 設定ディレクトリのパス(デフォルト: ~/.papycli)
|
|
256
|
+
PAPYCLI_CUSTOM_HEADER すべてのリクエストに適用するカスタム HTTP ヘッダー
|
|
257
|
+
複数のヘッダーは改行で区切る:
|
|
258
|
+
export PAPYCLI_CUSTOM_HEADER=$'Authorization: Bearer token\nX-Tenant: acme'
|
|
259
|
+
PAPYCLI_DISABLE_DOTENV 1 に設定すると .env ファイルの自動読み込みを無効化する。
|
|
260
|
+
デフォルトでは起動時にカレントディレクトリと
|
|
261
|
+
$PAPYCLI_CONF_DIR の .env を読み込む。信頼できない
|
|
262
|
+
ディレクトリで実行する際は無効化を推奨する:
|
|
263
|
+
export PAPYCLI_DISABLE_DOTENV=1
|
|
259
264
|
```
|
|
260
265
|
|
|
261
266
|
---
|
|
@@ -253,10 +253,15 @@ Options:
|
|
|
253
253
|
--help / -h Show help
|
|
254
254
|
|
|
255
255
|
Environment variables:
|
|
256
|
-
PAPYCLI_CONF_DIR
|
|
257
|
-
PAPYCLI_CUSTOM_HEADER
|
|
258
|
-
|
|
259
|
-
|
|
256
|
+
PAPYCLI_CONF_DIR Path to the config directory (default: ~/.papycli)
|
|
257
|
+
PAPYCLI_CUSTOM_HEADER Custom HTTP headers applied to every request.
|
|
258
|
+
Separate multiple headers with newlines:
|
|
259
|
+
export PAPYCLI_CUSTOM_HEADER=$'Authorization: Bearer token\nX-Tenant: acme'
|
|
260
|
+
PAPYCLI_DISABLE_DOTENV Set to 1 to disable automatic .env file loading.
|
|
261
|
+
By default papycli loads .env from the current directory
|
|
262
|
+
and $PAPYCLI_CONF_DIR on startup. Disable this when running
|
|
263
|
+
in untrusted directories to prevent unintended env injection:
|
|
264
|
+
export PAPYCLI_DISABLE_DOTENV=1
|
|
260
265
|
```
|
|
261
266
|
|
|
262
267
|
---
|
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
# config add --upgrade Implementation Plan
|
|
2
|
+
|
|
3
|
+
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|
4
|
+
|
|
5
|
+
**Goal:** `papycli config add` を新規登録専用にし、既存 API の更新には `--upgrade` フラグを必須とする。
|
|
6
|
+
|
|
7
|
+
**Architecture:** `src/papycli/main.py` の `cmd_config_add` にのみ変更を加える。`--upgrade` フラグ追加・既存 API チェック・出力メッセージの分岐のすべてをこの関数内で完結させる。`init_cmd.py` は変更しない。
|
|
8
|
+
|
|
9
|
+
**Tech Stack:** Python 3.12, click, pytest, Click CliRunner (テスト)
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## ファイルマップ
|
|
14
|
+
|
|
15
|
+
| ファイル | 変更種別 | 内容 |
|
|
16
|
+
|---|---|---|
|
|
17
|
+
| `src/papycli/main.py` | 修正 | `cmd_config_add` に `--upgrade` フラグと既存 API チェックを追加 |
|
|
18
|
+
| `tests/unittest/test_main.py` | 修正 | `--upgrade` 関連テストを追加 |
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
### Task 1: 既存 API への `config add` がエラーになるテストを書く
|
|
23
|
+
|
|
24
|
+
**Files:**
|
|
25
|
+
- Modify: `tests/unittest/test_main.py`
|
|
26
|
+
|
|
27
|
+
- [ ] **Step 1: 失敗するテストを書く**
|
|
28
|
+
|
|
29
|
+
`tests/unittest/test_main.py` の `# papycli config add` セクション末尾に以下を追加する:
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
def test_cmd_add_already_registered_errors(
|
|
33
|
+
tmp_path: Path, minimal_spec_file: Path, monkeypatch: pytest.MonkeyPatch
|
|
34
|
+
) -> None:
|
|
35
|
+
"""config add を同じ API 名で2回実行するとエラーになる。"""
|
|
36
|
+
monkeypatch.setenv("PAPYCLI_CONF_DIR", str(tmp_path))
|
|
37
|
+
runner = CliRunner()
|
|
38
|
+
runner.invoke(cli, ["config", "add", str(minimal_spec_file)])
|
|
39
|
+
result = runner.invoke(cli, ["config", "add", str(minimal_spec_file)])
|
|
40
|
+
assert result.exit_code != 0
|
|
41
|
+
assert "already registered" in result.output
|
|
42
|
+
assert "--upgrade" in result.output
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
- [ ] **Step 2: テストが失敗することを確認する**
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
uv run pytest tests/unittest/test_main.py::test_cmd_add_already_registered_errors -v
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Expected: FAIL(現状は2回目も exit 0 で成功してしまう)
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
### Task 2: `config add` に既存 API チェックを実装する
|
|
56
|
+
|
|
57
|
+
**Files:**
|
|
58
|
+
- Modify: `src/papycli/main.py:85-119`
|
|
59
|
+
|
|
60
|
+
- [ ] **Step 1: `--upgrade` フラグと既存チェックを追加する**
|
|
61
|
+
|
|
62
|
+
`main.py` の `cmd_config_add` コマンド定義を以下のように変更する:
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
@cmd_config.command(
|
|
66
|
+
"add",
|
|
67
|
+
help=h(
|
|
68
|
+
"Register an API from an OpenAPI spec file.",
|
|
69
|
+
"OpenAPI spec ファイルから API を登録する。",
|
|
70
|
+
),
|
|
71
|
+
)
|
|
72
|
+
@click.argument("spec_file", metavar="SPEC_FILE", type=click.Path(exists=True, dir_okay=False))
|
|
73
|
+
@click.option(
|
|
74
|
+
"--upgrade", "upgrade", is_flag=True,
|
|
75
|
+
help=h(
|
|
76
|
+
"Update an existing registered API with a new spec.",
|
|
77
|
+
"既存の登録済み API を新しい spec で更新する。",
|
|
78
|
+
),
|
|
79
|
+
)
|
|
80
|
+
def cmd_config_add(spec_file: str, upgrade: bool) -> None:
|
|
81
|
+
spec_path = Path(spec_file)
|
|
82
|
+
conf_dir = get_conf_dir()
|
|
83
|
+
|
|
84
|
+
if spec_path.stem in ("default", "aliases"):
|
|
85
|
+
click.echo(
|
|
86
|
+
f"Error: '{spec_path.stem}' is a reserved name and cannot be used as an API name.",
|
|
87
|
+
err=True,
|
|
88
|
+
)
|
|
89
|
+
sys.exit(1)
|
|
90
|
+
|
|
91
|
+
conf = load_conf(conf_dir)
|
|
92
|
+
api_name = spec_path.stem
|
|
93
|
+
already_registered = api_name in conf and isinstance(conf[api_name], dict)
|
|
94
|
+
|
|
95
|
+
if not upgrade and already_registered:
|
|
96
|
+
click.echo(
|
|
97
|
+
f"Error: API '{api_name}' is already registered. Use --upgrade to update it.",
|
|
98
|
+
err=True,
|
|
99
|
+
)
|
|
100
|
+
sys.exit(1)
|
|
101
|
+
|
|
102
|
+
try:
|
|
103
|
+
api_name, base_url = init_api(spec_path, conf_dir)
|
|
104
|
+
except Exception as e:
|
|
105
|
+
click.echo(f"Error: {e}", err=True)
|
|
106
|
+
sys.exit(1)
|
|
107
|
+
|
|
108
|
+
register_initialized_api(conf, api_name, spec_path, base_url)
|
|
109
|
+
save_conf(conf, conf_dir)
|
|
110
|
+
|
|
111
|
+
if upgrade and already_registered:
|
|
112
|
+
click.echo(f"Updated API '{api_name}'")
|
|
113
|
+
else:
|
|
114
|
+
click.echo(f"Registered API '{api_name}'")
|
|
115
|
+
if base_url:
|
|
116
|
+
click.echo(f" Base URL : {base_url}")
|
|
117
|
+
else:
|
|
118
|
+
click.echo(" Base URL : (not set — edit papycli.conf to add url)")
|
|
119
|
+
click.echo(f" Conf dir : {conf_dir}")
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
- [ ] **Step 2: Task 1 のテストが通ることを確認する**
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
uv run pytest tests/unittest/test_main.py::test_cmd_add_already_registered_errors -v
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Expected: PASS
|
|
129
|
+
|
|
130
|
+
- [ ] **Step 3: 既存テストが壊れていないことを確認する**
|
|
131
|
+
|
|
132
|
+
```
|
|
133
|
+
uv run pytest tests/unittest/test_main.py -v
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Expected: すべて PASS
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
### Task 3: `--upgrade` で既存 API を更新するテストを書いて通す
|
|
141
|
+
|
|
142
|
+
**Files:**
|
|
143
|
+
- Modify: `tests/unittest/test_main.py`
|
|
144
|
+
|
|
145
|
+
- [ ] **Step 1: テストを書く**
|
|
146
|
+
|
|
147
|
+
`test_cmd_add_already_registered_errors` の直後に以下を追加する:
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
def test_cmd_add_upgrade_updates_existing(
|
|
151
|
+
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
152
|
+
) -> None:
|
|
153
|
+
"""--upgrade で既存 API の spec・apidef・URL が更新される。"""
|
|
154
|
+
monkeypatch.setenv("PAPYCLI_CONF_DIR", str(tmp_path))
|
|
155
|
+
runner = CliRunner()
|
|
156
|
+
|
|
157
|
+
# 旧 spec で登録
|
|
158
|
+
old_spec: dict[str, Any] = {
|
|
159
|
+
"openapi": "3.0.2",
|
|
160
|
+
"servers": [{"url": "http://old.example.com/api"}],
|
|
161
|
+
"paths": {
|
|
162
|
+
"/items": {"get": {"parameters": []}},
|
|
163
|
+
},
|
|
164
|
+
}
|
|
165
|
+
spec_file = tmp_path / "myapi.json"
|
|
166
|
+
spec_file.write_text(json.dumps(old_spec), encoding="utf-8")
|
|
167
|
+
runner.invoke(cli, ["config", "add", str(spec_file)])
|
|
168
|
+
|
|
169
|
+
# 新 spec で --upgrade
|
|
170
|
+
new_spec: dict[str, Any] = {
|
|
171
|
+
"openapi": "3.0.2",
|
|
172
|
+
"servers": [{"url": "http://new.example.com/api"}],
|
|
173
|
+
"paths": {
|
|
174
|
+
"/items": {"get": {"parameters": []}},
|
|
175
|
+
"/users": {"get": {"parameters": []}},
|
|
176
|
+
},
|
|
177
|
+
}
|
|
178
|
+
spec_file.write_text(json.dumps(new_spec), encoding="utf-8")
|
|
179
|
+
result = runner.invoke(cli, ["config", "add", "--upgrade", str(spec_file)])
|
|
180
|
+
|
|
181
|
+
assert result.exit_code == 0
|
|
182
|
+
assert "Updated API 'myapi'" in result.output
|
|
183
|
+
assert "http://new.example.com/api" in result.output
|
|
184
|
+
|
|
185
|
+
conf = json.loads((tmp_path / "papycli.conf").read_text(encoding="utf-8"))
|
|
186
|
+
assert conf["myapi"]["url"] == "http://new.example.com/api"
|
|
187
|
+
|
|
188
|
+
apidef = json.loads((tmp_path / "apis" / "myapi.json").read_text(encoding="utf-8"))
|
|
189
|
+
assert "/users" in apidef
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def test_cmd_add_upgrade_on_new_api_registers(
|
|
193
|
+
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
194
|
+
) -> None:
|
|
195
|
+
"""--upgrade で未登録 API を指定すると新規登録として扱われる。"""
|
|
196
|
+
monkeypatch.setenv("PAPYCLI_CONF_DIR", str(tmp_path))
|
|
197
|
+
spec: dict[str, Any] = {
|
|
198
|
+
"openapi": "3.0.2",
|
|
199
|
+
"servers": [{"url": "http://localhost:9000/api"}],
|
|
200
|
+
"paths": {"/items": {"get": {"parameters": []}}},
|
|
201
|
+
}
|
|
202
|
+
spec_file = tmp_path / "myapi.json"
|
|
203
|
+
spec_file.write_text(json.dumps(spec), encoding="utf-8")
|
|
204
|
+
|
|
205
|
+
runner = CliRunner()
|
|
206
|
+
result = runner.invoke(cli, ["config", "add", "--upgrade", str(spec_file)])
|
|
207
|
+
|
|
208
|
+
assert result.exit_code == 0
|
|
209
|
+
assert "Registered API 'myapi'" in result.output
|
|
210
|
+
conf = json.loads((tmp_path / "papycli.conf").read_text(encoding="utf-8"))
|
|
211
|
+
assert conf["default"] == "myapi"
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
- [ ] **Step 2: テストが通ることを確認する**
|
|
215
|
+
|
|
216
|
+
```
|
|
217
|
+
uv run pytest tests/unittest/test_main.py::test_cmd_add_upgrade_updates_existing tests/unittest/test_main.py::test_cmd_add_upgrade_on_new_api_registers -v
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Expected: 両方 PASS
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
### Task 4: Lint・型チェックを通してコミットする
|
|
225
|
+
|
|
226
|
+
**Files:**
|
|
227
|
+
- No new files
|
|
228
|
+
|
|
229
|
+
- [ ] **Step 1: ruff チェック**
|
|
230
|
+
|
|
231
|
+
```
|
|
232
|
+
uv run ruff check src/papycli/main.py tests/unittest/test_main.py
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Expected: 警告・エラーなし
|
|
236
|
+
|
|
237
|
+
- [ ] **Step 2: ruff フォーマット**
|
|
238
|
+
|
|
239
|
+
```
|
|
240
|
+
uv run ruff format src/papycli/main.py tests/unittest/test_main.py
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
- [ ] **Step 3: mypy チェック**
|
|
244
|
+
|
|
245
|
+
```
|
|
246
|
+
uv run mypy src/
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
Expected: エラーなし
|
|
250
|
+
|
|
251
|
+
- [ ] **Step 4: テストスイート全体を実行する**
|
|
252
|
+
|
|
253
|
+
```
|
|
254
|
+
uv run pytest tests/unittest/ -v
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
Expected: すべて PASS
|
|
258
|
+
|
|
259
|
+
- [ ] **Step 5: コミットする**
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
git add src/papycli/main.py tests/unittest/test_main.py
|
|
263
|
+
git commit -m "feat: add --upgrade option to config add command"
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
### Task 5: GitHub issue を作成してトピックブランチを切る
|
|
269
|
+
|
|
270
|
+
> このタスクは実装前に行う(issue → branch の順)。Task 1 の前に実施すること。
|
|
271
|
+
|
|
272
|
+
- [ ] **Step 1: issue を作成する**
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
gh issue create \
|
|
276
|
+
--title "feat: config add に --upgrade オプションを追加する" \
|
|
277
|
+
--label "feature" \
|
|
278
|
+
--body "$(cat <<'EOF'
|
|
279
|
+
## 概要
|
|
280
|
+
|
|
281
|
+
\`papycli config add\` コマンドに \`--upgrade\` オプションを追加する。
|
|
282
|
+
|
|
283
|
+
## 動作
|
|
284
|
+
|
|
285
|
+
- \`config add <spec>\`: 新規登録専用。既存 API 名があればエラー。
|
|
286
|
+
- \`config add --upgrade <spec>\`: 既存 API の spec・apidef・URL を更新する。未登録の場合は新規登録。
|
|
287
|
+
|
|
288
|
+
## 参考
|
|
289
|
+
|
|
290
|
+
設計書: \`docs/superpowers/specs/2026-04-01-config-add-upgrade-design.md\`
|
|
291
|
+
EOF
|
|
292
|
+
)"
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
- [ ] **Step 2: issue 番号を確認してトピックブランチを作成する**
|
|
296
|
+
|
|
297
|
+
(issue 番号を `<N>` に置き換えて実行する)
|
|
298
|
+
|
|
299
|
+
```bash
|
|
300
|
+
git checkout main
|
|
301
|
+
git pull
|
|
302
|
+
git checkout -b feature/config-add-upgrade-<N>
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
### Task 6: PR を作成する
|
|
308
|
+
|
|
309
|
+
- [ ] **Step 1: push する**
|
|
310
|
+
|
|
311
|
+
```bash
|
|
312
|
+
git push -u origin feature/config-add-upgrade-<N>
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
- [ ] **Step 2: PR を作成する**
|
|
316
|
+
|
|
317
|
+
(issue 番号を `<N>` に置き換えて実行する)
|
|
318
|
+
|
|
319
|
+
```bash
|
|
320
|
+
gh pr create \
|
|
321
|
+
--title "feat: config add に --upgrade オプションを追加する" \
|
|
322
|
+
--body "$(cat <<'EOF'
|
|
323
|
+
## Summary
|
|
324
|
+
|
|
325
|
+
- \`papycli config add\` を新規登録専用に変更し、既存 API への再登録はエラーにする
|
|
326
|
+
- \`--upgrade\` フラグを追加し、既存 API の spec・apidef・base URL を更新できるようにする
|
|
327
|
+
- \`--upgrade\` で未登録 API を指定した場合は新規登録として扱う
|
|
328
|
+
|
|
329
|
+
Closes #<N>
|
|
330
|
+
|
|
331
|
+
## Test plan
|
|
332
|
+
|
|
333
|
+
- [ ] \`config add\` で既存 API 名を指定するとエラー終了・"already registered" メッセージが出る
|
|
334
|
+
- [ ] \`config add --upgrade\` で既存 API を更新すると conf と apidef が書き換わる
|
|
335
|
+
- [ ] \`config add --upgrade\` で未登録 API を指定すると新規登録される
|
|
336
|
+
- [ ] \`uv run pytest tests/unittest/\` がすべて PASS する
|
|
337
|
+
|
|
338
|
+
🤖 Generated with [Claude Code](https://claude.com/claude-code)
|
|
339
|
+
EOF
|
|
340
|
+
)"
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
---
|
|
344
|
+
|
|
345
|
+
## 実行順序
|
|
346
|
+
|
|
347
|
+
Tasks は以下の順で実行する:
|
|
348
|
+
|
|
349
|
+
1. **Task 5**(issue 作成・ブランチ作成)
|
|
350
|
+
2. **Task 1**(失敗テスト追加)
|
|
351
|
+
3. **Task 2**(実装)
|
|
352
|
+
4. **Task 3**(upgrade テスト追加・確認)
|
|
353
|
+
5. **Task 4**(lint・型チェック・コミット)
|
|
354
|
+
6. **Task 6**(PR 作成)
|