diff --git a/ansibleplaybookgrapher/graph_model.py b/ansibleplaybookgrapher/graph_model.py index 95b1c7cd..f70eeb82 100644 --- a/ansibleplaybookgrapher/graph_model.py +++ b/ansibleplaybookgrapher/graph_model.py @@ -580,25 +580,30 @@ def handlers(self) -> list["HandlerNode"]: """ return self.get_nodes("handlers") - def get_handlers(self, notify: list[str]) -> list["HandlerNode"]: + def get_notified_handlers( + self, notify: list[str] + ) -> tuple[list["HandlerNode"], list[str]]: """Return the handlers notified by the given names if they exist You must calculate the indices before calling this method. - :param notify: The name of the handler to get. - :return: + :param notify: The names of the handler to get from the play. + :return: A tuple of the notified handlers and the names of the handlers that were not found. """ - # TODO: add a warning when a notified handler is not found - result = [] + notified_handlers: list[HandlerNode] = [] + found: set[str] = set() + for h in reversed(self.handlers): - if h in result: + if h in notified_handlers: continue for n in notify: if h.matches_handler(n): - result.append(h) + notified_handlers.append(h) + found.add(n) - return sorted(result, key=lambda x: x.index) + not_found = set(notify) - found + return sorted(notified_handlers, key=lambda x: x.index), list(not_found) def to_dict( self, diff --git a/ansibleplaybookgrapher/renderer/__init__.py b/ansibleplaybookgrapher/renderer/__init__.py index 5dd4862b..6cbd8496 100644 --- a/ansibleplaybookgrapher/renderer/__init__.py +++ b/ansibleplaybookgrapher/renderer/__init__.py @@ -319,3 +319,19 @@ def get_node_url(self, node: Node) -> str | None: return url return None + + +def log_handlers_not_found( + play_node: PlayNode, task_node: TaskNode, handlers_not_found: list[str] +) -> None: + """Log the handlers that have not been found. + + :param play_node: The play node + :param task_node: The task node + :param handlers_not_found: The handlers that have not been found. + :return: + """ + for handler in handlers_not_found: + display.warning( + f"The handler '{handler}' notified by the task '{task_node.display_name()}' has not been found in the play '{play_node.display_name()}'." + ) diff --git a/ansibleplaybookgrapher/renderer/graphviz/__init__.py b/ansibleplaybookgrapher/renderer/graphviz/__init__.py index 05243add..e9a31a25 100644 --- a/ansibleplaybookgrapher/renderer/graphviz/__init__.py +++ b/ansibleplaybookgrapher/renderer/graphviz/__init__.py @@ -25,7 +25,11 @@ RoleNode, TaskNode, ) -from ansibleplaybookgrapher.renderer import PlaybookBuilder, Renderer +from ansibleplaybookgrapher.renderer import ( + PlaybookBuilder, + Renderer, + log_handlers_not_found, +) from ansibleplaybookgrapher.renderer.graphviz.postprocessor import GraphvizPostProcessor display = Display() @@ -206,7 +210,10 @@ def build_task( # Build the edge from the task to the handlers it notifies if self.show_handlers: - notified_handlers = play_node.get_handlers(task_node.notify) + notified_handlers, not_found = play_node.get_notified_handlers( + task_node.notify + ) + log_handlers_not_found(play_node, task_node, not_found) for counter, handler in enumerate(notified_handlers, 1): digraph.edge( diff --git a/ansibleplaybookgrapher/renderer/mermaid.py b/ansibleplaybookgrapher/renderer/mermaid.py index b1043c66..fec5bcc5 100644 --- a/ansibleplaybookgrapher/renderer/mermaid.py +++ b/ansibleplaybookgrapher/renderer/mermaid.py @@ -29,7 +29,11 @@ RoleNode, TaskNode, ) -from ansibleplaybookgrapher.renderer import PlaybookBuilder, Renderer +from ansibleplaybookgrapher.renderer import ( + PlaybookBuilder, + Renderer, + log_handlers_not_found, +) display = Display() @@ -288,7 +292,10 @@ def build_task( ) if self.show_handlers: - notified_handlers = play_node.get_handlers(task_node.notify) + notified_handlers, not_found = play_node.get_notified_handlers( + task_node.notify + ) + log_handlers_not_found(play_node, task_node, not_found) for counter, handler in enumerate(notified_handlers, 1): self.add_link( diff --git a/tests/test_graph_model.py b/tests/test_graph_model.py index d577f913..23b9a5d5 100644 --- a/tests/test_graph_model.py +++ b/tests/test_graph_model.py @@ -308,13 +308,16 @@ def test_get_handlers_from_play(): play.calculate_indices() - assert play.get_handlers(["fake handler"]) == [] - assert play.get_handlers(["restart nginx"]) == [restart_nginx] - assert play.get_handlers(["restart postgres"]) == [restart_postgres] + assert play.get_notified_handlers(["fake handler"]) == ([], ["fake handler"]) + assert play.get_notified_handlers(["restart nginx"]) == ([restart_nginx], []) + assert play.get_notified_handlers(["restart postgres"]) == ([restart_postgres], []) - mysql_handlers = play.get_handlers(["restart mysql"]) + mysql_handlers, _ = play.get_notified_handlers(["restart mysql"]) assert len(mysql_handlers) == 1 assert mysql_handlers[0].id == restart_mysql_2.id # When multiple handlers have the same listen, we return them in the order they are defined - assert play.get_handlers(["restart dbs"]) == [restart_postgres, restart_mysql_2] + assert play.get_notified_handlers(["restart dbs"]) == ( + [restart_postgres, restart_mysql_2], + [], + )