diff --git a/changelog/1263.fixed.md b/changelog/1263.fixed.md new file mode 100644 index 000000000..f2a23fd7e --- /dev/null +++ b/changelog/1263.fixed.md @@ -0,0 +1 @@ +Fixed `client.branch.validate()` and `infrahubctl branch validate`, which raised a `GraphQLError` against every supported Infrahub server because the mutation requested a `messages` field that was removed from `BranchValidate` in Infrahub 1.1.0. diff --git a/infrahub_sdk/branch.py b/infrahub_sdk/branch.py index b310522e4..4d760573d 100644 --- a/infrahub_sdk/branch.py +++ b/infrahub_sdk/branch.py @@ -133,14 +133,7 @@ async def validate(self, branch_name: str) -> BranchData: } } - query_data = { - "ok": None, - "messages": None, - "object": { - "id": None, - "name": None, - }, - } + query_data = {"ok": None} query = Mutation(mutation="BranchValidate", input_data=input_data, query=query_data) response = await self.client.execute_graphql(query=query.render(), tracker="mutation-branch-validate") @@ -288,14 +281,7 @@ def validate(self, branch_name: str) -> BranchData: } } - query_data = { - "ok": None, - "messages": None, - "object": { - "id": None, - "name": None, - }, - } + query_data = {"ok": None} query = Mutation(mutation="BranchValidate", input_data=input_data, query=query_data) response = self.client.execute_graphql(query=query.render(), tracker="mutation-branch-validate") diff --git a/tests/integration/test_infrahub_client.py b/tests/integration/test_infrahub_client.py index 54be643ac..bc39c2320 100644 --- a/tests/integration/test_infrahub_client.py +++ b/tests/integration/test_infrahub_client.py @@ -63,6 +63,9 @@ async def test_branch_delete(self, client: InfrahubClient, base_dataset: None) - assert async_branch in pre_delete assert async_branch not in post_delete + async def test_branch_validate(self, client: InfrahubClient, base_dataset: None) -> None: + assert await client.branch.validate(branch_name="branch01") is True + async def test_get_all(self, client: InfrahubClient, base_dataset: None) -> None: nodes = await client.all(kind=TESTING_CAT) assert len(nodes) == 2 diff --git a/tests/integration/test_infrahub_client_sync.py b/tests/integration/test_infrahub_client_sync.py index 34c91a446..57d7c842e 100644 --- a/tests/integration/test_infrahub_client_sync.py +++ b/tests/integration/test_infrahub_client_sync.py @@ -59,6 +59,9 @@ def test_branch_delete(self, client_sync: InfrahubClientSync, base_dataset: None assert sync_branch in pre_delete assert sync_branch not in post_delete + def test_branch_validate(self, client_sync: InfrahubClientSync, base_dataset: None) -> None: + assert client_sync.branch.validate(branch_name="sync-branch01") is True + def test_get_all(self, client_sync: InfrahubClientSync, base_dataset: None) -> None: nodes = client_sync.all(kind=TESTING_CAT) assert len(nodes) == 2 diff --git a/tests/unit/sdk/test_branch.py b/tests/unit/sdk/test_branch.py index a86182e9e..87eeadd66 100644 --- a/tests/unit/sdk/test_branch.py +++ b/tests/unit/sdk/test_branch.py @@ -49,6 +49,33 @@ async def test_get_branches(clients: BothClients, mock_branches_list_query: HTTP assert isinstance(branches["main"], BranchData) +@pytest.mark.parametrize("client_type", client_types) +async def test_branch_validate_query_excludes_removed_fields( + httpx_mock: HTTPXMock, clients: BothClients, client_type: str +) -> None: + """validate() must only request fields the BranchValidate mutation still exposes. + + The server removed the `messages` field from BranchValidate, so the rendered + mutation must not request it, otherwise the server rejects the whole query. + """ + httpx_mock.add_response( + method="POST", + json={"data": {"BranchValidate": {"ok": True}}}, + match_headers={"X-Infrahub-Tracker": "mutation-branch-validate"}, + ) + + if client_type == "standard": + result = await clients.standard.branch.validate(branch_name="branch01") + else: + result = clients.sync.branch.validate(branch_name="branch01") + + assert result is True + + post_requests = [r for r in httpx_mock.get_requests() if r.method == "POST"] + assert len(post_requests) == 1 + assert b"messages" not in post_requests[0].content + + @pytest.mark.parametrize("client_type", client_types) async def test_branch_merge_enforces_minimum_timeout( httpx_mock: HTTPXMock, clients: BothClients, client_type: str