diff --git a/changelog/529.added.md b/changelog/529.added.md new file mode 100644 index 00000000..cb02de4f --- /dev/null +++ b/changelog/529.added.md @@ -0,0 +1,2 @@ +Add `create_diff` method to create a diff summary between two timestamps +Update `get_diff_summary` to accept optional time range parameters \ No newline at end of file diff --git a/infrahub_sdk/client.py b/infrahub_sdk/client.py index 6c4ab7ab..0b5752c8 100644 --- a/infrahub_sdk/client.py +++ b/infrahub_sdk/client.py @@ -5,6 +5,7 @@ import logging import time from collections.abc import Coroutine, MutableMapping +from datetime import datetime from functools import wraps from time import sleep from typing import ( @@ -24,6 +25,7 @@ from .batch import InfrahubBatch, InfrahubBatchSync from .branch import ( + MUTATION_QUERY_TASK, BranchData, InfrahubBranchManager, InfrahubBranchManagerSync, @@ -1149,21 +1151,57 @@ async def query_gql_query( return decode_json(response=resp) + async def create_diff( + self, branch: str, name: str, from_time: datetime, to_time: datetime, wait_until_completion: bool = True + ) -> bool | str: + if from_time > to_time: + raise ValueError("from_time must be <= to_time") + input_data = { + "wait_until_completion": wait_until_completion, + "data": { + "name": name, + "branch": branch, + "from_time": from_time.isoformat(), + "to_time": to_time.isoformat(), + }, + } + + mutation_query = MUTATION_QUERY_TASK if not wait_until_completion else {"ok": None} + query = Mutation(mutation="DiffUpdate", input_data=input_data, query=mutation_query) + response = await self.execute_graphql(query=query.render(), tracker="mutation-diff-update") + + if not wait_until_completion and "task" in response["DiffUpdate"]: + return response["DiffUpdate"]["task"]["id"] + + return response["DiffUpdate"]["ok"] + async def get_diff_summary( self, branch: str, + name: str | None = None, + from_time: datetime | None = None, + to_time: datetime | None = None, timeout: int | None = None, tracker: str | None = None, raise_for_error: bool = True, ) -> list[NodeDiff]: query = get_diff_summary_query() + input_data = {"branch_name": branch} + if name: + input_data["name"] = name + if from_time and to_time and from_time > to_time: + raise ValueError("from_time must be <= to_time") + if from_time: + input_data["from_time"] = from_time.isoformat() + if to_time: + input_data["to_time"] = to_time.isoformat() response = await self.execute_graphql( query=query, branch_name=branch, timeout=timeout, tracker=tracker, raise_for_error=raise_for_error, - variables={"branch_name": branch}, + variables=input_data, ) node_diffs: list[NodeDiff] = [] @@ -2286,21 +2324,57 @@ def query_gql_query( return decode_json(response=resp) + def create_diff( + self, branch: str, name: str, from_time: datetime, to_time: datetime, wait_until_completion: bool = True + ) -> bool | str: + if from_time > to_time: + raise ValueError("from_time must be <= to_time") + input_data = { + "wait_until_completion": wait_until_completion, + "data": { + "name": name, + "branch": branch, + "from_time": from_time.isoformat(), + "to_time": to_time.isoformat(), + }, + } + + mutation_query = MUTATION_QUERY_TASK if not wait_until_completion else {"ok": None} + query = Mutation(mutation="DiffUpdate", input_data=input_data, query=mutation_query) + response = self.execute_graphql(query=query.render(), tracker="mutation-diff-update") + + if not wait_until_completion and "task" in response["DiffUpdate"]: + return response["DiffUpdate"]["task"]["id"] + + return response["DiffUpdate"]["ok"] + def get_diff_summary( self, branch: str, + name: str | None = None, + from_time: datetime | None = None, + to_time: datetime | None = None, timeout: int | None = None, tracker: str | None = None, raise_for_error: bool = True, ) -> list[NodeDiff]: query = get_diff_summary_query() + input_data = {"branch_name": branch} + if name: + input_data["name"] = name + if from_time and to_time and from_time > to_time: + raise ValueError("from_time must be <= to_time") + if from_time: + input_data["from_time"] = from_time.isoformat() + if to_time: + input_data["to_time"] = to_time.isoformat() response = self.execute_graphql( query=query, branch_name=branch, timeout=timeout, tracker=tracker, raise_for_error=raise_for_error, - variables={"branch_name": branch}, + variables=input_data, ) node_diffs: list[NodeDiff] = [] diff --git a/infrahub_sdk/diff.py b/infrahub_sdk/diff.py index c445000f..6b17b147 100644 --- a/infrahub_sdk/diff.py +++ b/infrahub_sdk/diff.py @@ -37,8 +37,8 @@ class NodeDiffPeer(TypedDict): def get_diff_summary_query() -> str: return """ - query GetDiffTree($branch_name: String!) { - DiffTree(branch: $branch_name) { + query GetDiffTree($branch_name: String!, $name: String, $from_time: DateTime, $to_time: DateTime) { + DiffTree(branch: $branch_name, name: $name, from_time: $from_time, to_time: $to_time) { nodes { uuid kind @@ -121,7 +121,7 @@ def diff_tree_node_to_node_diff(node_dict: dict[str, Any], branch_name: str) -> branch=branch_name, kind=str(node_dict.get("kind")), id=str(node_dict.get("uuid")), - action=str(node_dict.get("action")), + action=str(node_dict.get("status")), display_label=str(node_dict.get("label")), elements=element_diffs, ) diff --git a/tests/unit/sdk/test_diff_summary.py b/tests/unit/sdk/test_diff_summary.py index 7a176b20..73832cab 100644 --- a/tests/unit/sdk/test_diff_summary.py +++ b/tests/unit/sdk/test_diff_summary.py @@ -109,7 +109,7 @@ async def test_diffsummary(clients: BothClients, mock_diff_tree_query, client_ty "branch": "branch2", "kind": "TestCar", "id": "17fbadf0-6637-4fa2-43e6-1677ea170e0f", - "action": "None", + "action": "UPDATED", "display_label": "nolt #444444", "elements": [ { @@ -124,7 +124,7 @@ async def test_diffsummary(clients: BothClients, mock_diff_tree_query, client_ty "branch": "branch2", "kind": "TestPerson", "id": "17fbadf0-634f-05a8-43e4-1677e744d4c0", - "action": "None", + "action": "UPDATED", "display_label": "Jane", "elements": [ { @@ -140,7 +140,7 @@ async def test_diffsummary(clients: BothClients, mock_diff_tree_query, client_ty "branch": "branch2", "kind": "TestPerson", "id": "17fbadf0-6243-5d3c-43ee-167718ff8dac", - "action": "None", + "action": "UPDATED", "display_label": "Jonathan", "elements": [ {