feat: Initial SDK — 117 endpoints across 18 mixins #2
No reviewers
Labels
No labels
domain:backend
domain:devops
domain:frontend
status:approved
status:in-progress
status:needs-fix
status:qa
type:bug
type:devops
type:feature
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
ldraney/woodpecker-sdk!2
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "1-initial-sdk-generate-from-swagger-json-f"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Changes
src/woodpecker_sdk/client.py:_BaseClientwith Bearer token auth + dual httpx clients (api + root),WoodpeckerClientcomposing all 18 mixinssrc/woodpecker_sdk/*.py: 18 mixin files — agents, badges, cron_jobs, debug, events, forges, organizations, pipeline_logs, pipeline_queues, pipelines, registries, repo_registries, repo_secrets, repositories, secrets, system, user, userstests/conftest.py: Session-scoped live client fixture loading creds from~/secrets/woodpecker/credentials.envtests/test_*.py: 18 test files, 33 tests passing, 2 skipped (SSE streaming + missing test data)pyproject.toml:ldraney-woodpecker-sdkv0.1.0, hatchling build, httpx depswagger.json: Source spec (117 endpoints, 22 tags)Test Plan
pytest tests/passes against live Woodpecker instance (33 passed, 2 skipped)pip install -e .worksissue-woodpecker-sdk-integration-testsReview Checklist
Related Notes
issue-woodpecker-sdk-initial— the issue this PR addressesplan-2026-02-28-woodpecker-sdk-mcp— Phase 1PR #2 Review: Woodpecker CI Python SDK (Phase 1)
Reviewed all 20 source files, 21 test files, pyproject.toml, and cross-referenced against all 117 swagger.json endpoints.
Blockers (must fix before merge)
B1.
debug.py-- 4 methods accept query parameters but silently drop themThe following methods accept keyword arguments from the caller but never forward them to the HTTP request. This is a correctness bug -- callers think they're configuring the request but the params are silently ignored.
pprof_goroutine(*, debug: int | None = None)--debugparam never passedpprof_heap(*, gc: str | None = None)--gcparam never passedpprof_profile(*, seconds: int)--secondsparam never passed (this one is required in the signature but still dropped!)pprof_trace(*, seconds: int)--secondsparam never passed (same -- required but dropped)Fix: each should pass
params={"debug": debug},params={"gc": gc},params={"seconds": seconds}respectively toself.get_bytes().pprof_profileandpprof_traceare the worst offenders becausesecondsis a required positional keyword -- the caller must provide it, but it gets thrown away.Nits (nice to fix, not blocking)
N1.
badges.pyimportsAnyfromtypingbut never uses itThe
BadgesMixinmethods returnstr, notAny. The import is dead code.N2. Duplicate
first_repofixture defined in 6 test filestest_badges.py,test_cron_jobs.py,test_pipelines.py,test_repo_registries.py,test_repo_secrets.py,test_repositories.pyeach define their own identicalfirst_repofixture. This should live once inconftest.py.N3.
test_agents.pyuses barereturninstead ofpytest.skip()when no data is availableLines 12 and 22 do
return # No agents to testwhich silently passes the test. Usingpytest.skip("No agents to test")would make the test report more honest about what was actually validated.N4.
from __future__ import annotationsis unnecessarypyproject.tomlrequirespython >= 3.10, where PEP 604 syntax (str | None) is native. The future import is harmless but adds noise to every file.N5. Test coverage is thin: 33/117 SDK methods are exercised (28%)
84 out of 117 public methods have zero test coverage. This is understandable for a generated SDK with integration tests (CUD operations are destructive), but worth noting. The read-only endpoints that ARE tested are sensible choices.
N6. Some tests would pass regardless of response shape
test_registries.pyandtest_secrets.pyeach have a single test that only checksisinstance(result, list). These are extremely weak assertions -- any list response (including an error envelope that happens to be a list) would pass.N7.
org_idtype inconsistency across mixins (matches swagger, still confusing)In
agents.py, org-scoped agent methods useorg_id: int. Inorganizations.py, all methods useorg_id: str. This matches the swagger spec (which itself is inconsistent), but it creates a confusing DX where the same conceptual parameter has different types depending on which method you call.Positive Observations
Full endpoint coverage: 117/117 -- Every single swagger endpoint is mapped to an SDK method. Verified by automated cross-reference of HTTP method + normalized path.
Clean mixin architecture -- The 18-mixin +
_BaseClientcomposition pattern is well-organized. Each mixin maps to a logical API domain. The MRO ordering inWoodpeckerClientis correct._BaseClientis solid -- Bearer auth via headers,raise_for_status()on every request,_clean_paramsstripsNonevalues, context manager support, separate_root_clientfor/healthzand/version. The dual-client approach for root vs/apipaths is a pragmatic and correct solution.Correct HTTP methods throughout -- Every endpoint uses the right HTTP verb (GET/POST/PATCH/DELETE) matching the swagger spec. No PUT/POST confusion.
204 handling --
post(),put(),patch(), anddelete()all correctly handle 204 No Content responses by returningNoneinstead of trying to parse empty JSON.Security -- No hardcoded secrets anywhere. Credentials loaded from env vars or
~/secrets/woodpecker/credentials.envin conftest. Token is optional (some endpoints like healthz don't need it).pyproject.tomlis correct -- hatchling build, proper package pathsrc/woodpecker_sdk, sensible deps (httpx>=0.27), dev deps for testing.Integration tests are pragmatic -- Tests that hit destructive endpoints (create/delete) are intentionally omitted. SSE endpoints are correctly skipped with a reason. Debug/pprof tests gracefully handle servers without debug mode enabled.
Endpoint Coverage Summary
Verdict
One blocker (debug.py dropped params), several minor nits. The core architecture, auth model, HTTP method correctness, and endpoint coverage are all solid. Fix the debug.py param forwarding and this is good to merge.