fix: allow null latest_released_version for unreleased custom connectors#80
fix: allow null latest_released_version for unreleased custom connectors#80okihus wants to merge 1 commit into
Conversation
The Workato API returns `null` for `latest_released_version` when a custom connector has no released versions yet (draft-only). The generated `CustomConnector` pydantic model declared this field as a non-nullable `StrictInt`, so any response containing such a connector would fail with a pydantic `ValidationError` and abort the entire list parse. This broke two commands for any workspace containing at least one draft-only custom connector: - `workato connectors list --custom` - `workato recipes validate` (calls `list_custom_connectors` to build its adapter whitelist before inspecting the recipe) Mark `latest_released_version` as `nullable: true` in the OpenAPI spec and regenerate the affected files via `make generate-client`.
There was a problem hiding this comment.
Pull request overview
Updates the Workato Platform CLI’s OpenAPI spec and regenerated client to correctly handle CustomConnector.latest_released_version being null for draft-only (unreleased) custom connectors, preventing pydantic validation failures when listing/validating recipes.
Changes:
- Mark
CustomConnector.latest_released_versionasnullable: truein the OpenAPI spec and add a clarifying description. - Regenerate the pydantic model so
latest_released_versionacceptsNoneand serializes it correctly when explicitly set. - Update generated model documentation to reflect the new field description.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
workato-api-spec.yaml |
Makes latest_released_version nullable and documents the null semantics for unreleased connectors. |
src/workato_platform_cli/client/workato_api/models/custom_connector.py |
Regenerates the model to accept Optional[StrictInt] and preserve explicit null in to_dict(). |
src/workato_platform_cli/client/workato_api/docs/CustomConnector.md |
Updates generated docs with the new field description. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| from pydantic import BaseModel, ConfigDict, Field, StrictInt, StrictStr | ||
| from typing import Any, ClassVar, Dict, List, Optional | ||
| from workato_platform_cli.client.workato_api.models.connector_version import ConnectorVersion | ||
| from typing import Optional, Set |
There was a problem hiding this comment.
Optional is imported twice (from typing import ... Optional and from typing import Optional, Set). This is redundant and can be consolidated into a single typing import to keep generated code clean and avoid potential lint churn if rules change.
| from typing import Optional, Set | |
| from typing import Set |
There was a problem hiding this comment.
The duplicate Optional import is pre-existing on main (a quirk of the python-asyncio generator template), not introduced by this PR — verified with git show main:src/workato_platform_cli/client/workato_api/models/custom_connector.py. Editing it here would diverge from make generate-client output, so the next regen would undo the fix.
Happy to file a separate issue for the generator config cleanup if useful — feels out of scope for this one-field-nullability fix.
Summary
CustomConnector.latest_released_versionis declared as non-nullableStrictIntin the OpenAPI spec and generated pydantic model, but the Workato API legitimately returnsnullfor this field on custom connectors that have no released versions yet (draft-only).Because pydantic validates the full list response, any single unreleased connector in a workspace breaks every CLI command that enumerates custom connectors:
workato connectors list --customworkato recipes validate—RecipeValidator.validate_recipecallslist_custom_connectors()atrecipes/validator.py:605to build its adapter whitelist before inspecting the recipe.Reproduction
Fix
latest_released_versionasnullable: trueinworkato-api-spec.yaml.make generate-client.The regenerated model becomes:
Test plan
uv run pytest tests/unit/— all passinguv run ruff check src/ tests/— cleanuv run ruff format --check src/ tests/— cleanconnectors list --customandrecipes validatesucceed.