diff --git a/CHANGELOG.md b/CHANGELOG.md index 94a65b9c..80ff5002 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,6 @@ # Unreleased + +# Released # v1.1.0 ## Features @@ -28,8 +30,13 @@ ### Pagination * Fixed `list_*` infinite-looping for API call which are non paginated, so they are now fetched with a single request. The generic list helper also treats any response without `meta.pagination` as a single complete page, preventing the same loop on other non-paginated endpoints. [#181](https://github.com/hashicorp/python-tfe/issues/181) +### Relationships +* Unified JSON:API relationship parsing into a single canonical helper, replacing the per-resource hand-rolled logic across runs, workspaces, no-code modules and more. [#180](https://github.com/hashicorp/python-tfe/pull/180) +* `?include=`'d relations are now fully hydrated from the response's `included` block (e.g. `workspace.current_run.status`) instead of being returned as id-only stubs. +* Models retain unknown server attributes in `model_extra` (`extra="allow"`) instead of silently dropping them, keeping output closer to the live API. +* Added missing `Workspace` fields `latest_run`, `latest_change_at`, `last_assessment_result_at`, and `source_module_id`, which previously raised `AttributeError`. [#179](https://github.com/hashicorp/python-tfe/issues/179) + -# Released # v1.0.0 ## Features diff --git a/pyproject.toml b/pyproject.toml index d1936cc1..46c7c495 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "pytfe" -version = "1.0.0" +version = "1.1.0" description = "Official Python SDK for HashiCorp Terraform Cloud / Terraform Enterprise (TFE) API v2" readme = "README.md" license = { text = "MPL-2.0" } diff --git a/src/pytfe/models/workspace.py b/src/pytfe/models/workspace.py index b6c52725..0dd7a8d4 100644 --- a/src/pytfe/models/workspace.py +++ b/src/pytfe/models/workspace.py @@ -171,6 +171,8 @@ class Workspace(BaseModel): source: WorkspaceSource | None = Field(None, alias="source") source_name: str | None = Field(None, alias="source-name") source_url: str | None = Field(None, alias="source-url") + # ID of the registry module a no-code workspace was provisioned from (#179). + source_module_id: str | None = Field(None, alias="source-module-id") structured_run_output_enabled: bool | None = Field( None, alias="structured-run-output-enabled" ) diff --git a/tests/units/test_workspace_jsonapi.py b/tests/units/test_workspace_jsonapi.py index af6dc528..ebe5d814 100644 --- a/tests/units/test_workspace_jsonapi.py +++ b/tests/units/test_workspace_jsonapi.py @@ -37,6 +37,15 @@ def test_new_attributes_parse_with_correct_types(self): # aliased KPI field still maps despite the divergent snake/hyphen names assert ws.runs_count == 3 + def test_source_module_id_parses_for_no_code_workspace(self): + # #179: no-code workspaces carry source-module-id; it must be a typed + # attribute, not buried in model_extra under the hyphenated wire key. + ws = _ws_from(_ws_payload(attributes={"source-module-id": "mod-ABC123"})) + assert ws.source_module_id == "mod-ABC123" + assert "source-module-id" not in (ws.model_extra or {}) + # absent on a normal workspace -> None, never an error + assert _ws_from(_ws_payload()).source_module_id is None + class TestForwardCompat: def test_unknown_attribute_survives_in_model_extra(self):