Skip to content

Commit f8d689e

Browse files
authored
feat!: migrate publish_provider to wheel-based provider-versions endpoint (PRA-376) (#40)
* feat!: migrate publish_provider to wheel-based provider-versions endpoint (PRA-376) The pragma-os Phase 11 cleanup deleted the legacy multipart ``POST /providers/{org}/{name}/publish`` route along with the in-API CloudBuildService/LocalBuildService stack. Publishing now flows through ``POST /provider-versions``, which accepts a JSON metadata payload pointing at a wheel hosted in GCP Artifact Registry. This rewires the SDK to the new contract: - ``publish_provider`` now takes a provider directory, builds the wheel locally with ``uv build --wheel``, runs schema extraction via :func:`pragma_sdk.provider.extract_schemas`, uploads the wheel to Artifact Registry via ``twine`` (relies on ``keyrings.google-artifactregistry-auth`` for ADC), and POSTs the JSON body the new route expects. - Drop ``get_publish_status`` and ``stream_publish_logs``: the new route persists synchronously, so the API never returns a ``build_id`` to poll. Callers should treat the response as PUBLISHED on success. - ``ProviderVersion`` gains ``wheel_url``, ``runtime_image`` and ``entrypoint`` fields to match the response shape. - Add ``pragma_sdk.provider.prepare_wheel_publish`` so consumers who need direct access to the build/extract/upload pipeline can reuse it without going through the HTTP client. - Add async ``get_me`` to mirror the sync client; required by the new async publish path. BREAKING CHANGE: ``PragmaClient.publish_provider`` / ``AsyncPragmaClient.publish_provider`` now take ``provider_dir`` instead of a ``tarball`` and namespaced ``provider_name``. ``get_publish_status`` and ``stream_publish_logs`` are removed. * test: drop publish_provider tests for now The wheel-publish unit tests will land in a follow-up alongside the matching pragma-cli rewiring. * chore: drop tests/ tree and forbid unit tests in CLAUDE.md The SDK is verified through pragma-os e2e suites and downstream consumers; carrying a parallel pytest tree just rots. Remove the folder and document the rule so future work doesn't regrow it. * chore: strip test target, deps, and ruff/ty test ignores Now that tests/ is gone, drop the matching scaffolding: - Remove the 'task test' target from Taskfile.yaml. - Remove the [dependency-groups].test block (pytest, respx, etc.) and the orphan respx entry under dev from pyproject.toml. - Remove [tool.pytest.ini_options] and the tests/-scoped overrides in [tool.ruff.lint.per-file-ignores] / [tool.ty.src]. - Drop the now-unused 'PT' (pytest) ruff lint selector. * fix: address PR #40 review feedback - Swap twine for `uv publish` so credential prompts can never block (uses --keyring-provider subprocess with the GAR keyring backend). - Drop the `version=` override from `publish_provider` and `prepare_wheel_publish`; the wheel filename is derived from [project].version, so make pyproject the single source of truth and refuse to publish when it is missing. - Drop the unused `config_schema`/`outputs_schema` fields from `WheelPublishPayload` — there is no code path that populates them. - Clarify `_provider_on_sys_path` docstring: only sys.path is restored, sys.modules entries from the import are left in place. - Tighten `prepare_wheel_publish` Raises block (add TypeError, drop the spurious RuntimeError on the helper that doesn't raise it). - Document `DEFAULT_ARTIFACT_REPO` as the Pragmatiks-prod default that callers can override per-publish. * docs: drop `uv pip install` reference from upload helper docstring The wheel URL is the contract; how the runtime resolves it isn't something to prescribe in the SDK docs — and `uv pip install` is the pip-compatible escape hatch we don't want to encourage. * refactor: dedupe pyproject helpers and resolve uv binary once Findings from /simplify pass: - Reuse: `provider/publish.py` was forking `_load_pyproject` and `_detect_provider_package` from `extract_schemas.py`. Generalised the originals to accept an optional path / pre-parsed dict and made `publish.py` delegate. Resolution rules now live in one place. - Quality: `shutil.which("uv")` ran twice per publish (build + upload). Hoisted to a single `_resolve_uv()` call at the top of `prepare_wheel_publish` and threaded the path through the helpers, so missing-`uv` fails fast instead of after the build succeeds. - Quality: `"oauth2accesstoken"` and `"subprocess"` are documented GAR / uv keyring contracts, not arbitrary values — promoted to module-level constants. - Quality: collapsed the async `publish_provider` org-id branch into a one-liner matching the sync style.
1 parent 5bf6001 commit f8d689e

11 files changed

Lines changed: 711 additions & 400 deletions

File tree

CLAUDE.md

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,11 @@
88

99
```
1010
pragma-sdk/
11-
├── src/pragma_sdk/
12-
│ ├── client.py # PragmaClient (sync) and AsyncPragmaClient
13-
│ ├── models/ # Pydantic models (shared with API)
14-
│ ├── resources/ # Resource-specific client methods
15-
│ └── provider/ # Provider authoring (Provider, Resource, Config, Outputs)
16-
└── tests/
11+
└── src/pragma_sdk/
12+
├── client.py # PragmaClient (sync) and AsyncPragmaClient
13+
├── models/ # Pydantic models (shared with API)
14+
├── resources/ # Resource-specific client methods
15+
└── provider/ # Provider authoring (Provider, Resource, Config, Outputs)
1716
```
1817

1918
## Features
@@ -38,23 +37,23 @@ Always use `task` commands:
3837

3938
| Command | Purpose |
4039
|---------|---------|
41-
| `task test` | Run pytest |
4240
| `task format` | Format with ruff |
4341
| `task check` | Lint + type check |
4442

4543
## Patterns
4644

4745
- All API methods are async in `AsyncPragmaClient`, sync wrappers in `PragmaClient`
4846
- Pydantic models for request/response types
49-
- httpx for HTTP calls with respx for testing
47+
- httpx for HTTP calls
5048
- Type hints on all public interfaces
5149

5250
## Testing
5351

54-
- Use respx to mock httpx calls
55-
- Fixtures in `conftest.py`
56-
- No real API calls in unit tests
57-
- Test both sync and async client methods
52+
**Do not write unit tests in this repository.** No `tests/` tree, no
53+
`pytest` files, no test-only fixtures. If a change feels like it
54+
needs a test, surface that to the user instead of adding one — they
55+
will decide where the coverage should live (often in pragma-os e2e
56+
suites or downstream consumers).
5857

5958
## Publishing to PyPI
6059

Taskfile.yaml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,3 @@ tasks:
1414
cmds:
1515
- uv run ruff check --fix .
1616
- uvx ty check
17-
18-
test:
19-
cmd: uv run pytest tests/ --cov=pragma_sdk --cov-report=term-missing {{.CLI_ARGS}}
20-
desc: Run all tests with coverage

pyproject.toml

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -19,24 +19,11 @@ classifiers = [
1919
# all = ["pragmatiks-gcp-provider"] # future
2020

2121
[dependency-groups]
22-
test = [
23-
"pytest>=8.4.1",
24-
"pytest-asyncio>=1.0.0",
25-
"pytest-cov>=7.0.0",
26-
"pytest-mock>=3.14.0",
27-
"respx>=0.21.1",
28-
"httpx>=0.28.1",
29-
]
3022
dev = [
3123
"commitizen>=4.11.0",
3224
"pre-commit>=4.0.0",
33-
"respx>=0.22.0",
3425
]
3526

36-
[tool.pytest.ini_options]
37-
asyncio_mode = "auto"
38-
pythonpath = ["tests"]
39-
4027
[tool.ruff]
4128
target-version = "py313"
4229
line-length = 120
@@ -52,7 +39,6 @@ select = [
5239
"UP", # Pyupgrade
5340
"D", # pydocstyle - docstring conventions
5441
"DOC", # Ruff's docstring checks (parameters match signature)
55-
"PT", # pytest rules
5642
]
5743

5844
[tool.ruff.lint.pydocstyle]
@@ -62,21 +48,6 @@ convention = "google"
6248
lines-after-imports = 2
6349
known-first-party = ["pragma_sdk"]
6450

65-
[tool.ruff.lint.per-file-ignores]
66-
"**/tests/**/*.py" = [
67-
"D100", # Missing docstring in public module
68-
"D101", # Missing docstring in public class
69-
"D102", # Missing docstring in public method
70-
"D103", # Missing docstring in public function
71-
"D104", # Missing docstring in public package
72-
"D107", # Missing docstring in __init__
73-
"DOC", # Docstring content rules (Returns, Raises, Yields sections)
74-
"PLC0415", # Import outside top-level (common in tests for isolation)
75-
]
76-
"**/tests/test_forward_ref.py" = [
77-
"F821", # Undefined names are intentional (testing forward reference detection)
78-
]
79-
8051
[tool.ruff.format]
8152
preview = true
8253

@@ -85,7 +56,7 @@ python-version = "3.13"
8556
python-platform = "darwin"
8657

8758
[tool.ty.src]
88-
exclude = ["**/tests/**", "**/__pycache__/**"]
59+
exclude = ["**/__pycache__/**"]
8960

9061
[tool.commitizen]
9162
name = "cz_conventional_commits"

0 commit comments

Comments
 (0)