Skip to content

Commit

Permalink
continue fixing
Browse files Browse the repository at this point in the history
  • Loading branch information
haidaraM committed Sep 8, 2024
1 parent e81dd13 commit 44f06cb
Show file tree
Hide file tree
Showing 12 changed files with 120 additions and 54 deletions.
5 changes: 5 additions & 0 deletions ansibleplaybookgrapher/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,7 @@
"""A command line tool to create a graph representing your Ansible playbook tasks and roles.
While you can use this package into another project, it is not primarily designed for that (yet).
"""

__version__ = "2.3.0"
__prog__ = "ansible-playbook-grapher"
9 changes: 8 additions & 1 deletion ansibleplaybookgrapher/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,13 @@ def init_parser(
desc: str | None = None,
epilog: str | None = None,
) -> None:
"""Create an options parser for the grapher.
:param usage:
:param desc:
:param epilog:
:return:
"""
super().init_parser(
usage=f"{__prog__} [options] playbook.yml",
desc="Make graphs from your Ansible Playbooks.",
Expand All @@ -273,7 +280,7 @@ def init_parser(

self._add_my_options()

def post_process_args(self, options: Namespace):
def post_process_args(self, options: Namespace) -> Namespace:
options = super().post_process_args(options)

# init the options
Expand Down
75 changes: 53 additions & 22 deletions ansibleplaybookgrapher/graph_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@ def __init__(
parent: "Node" = None,
index: int | None = None,
) -> None:
""":param node_name: The name of the node
"""
:param node_name: The name of the node
:param node_id: An identifier for this node
:param when: The conditional attached to the node
:param raw_object: The raw ansible object matching this node in the graph. Will be None if there is no match on
Expand All @@ -84,7 +86,8 @@ def __init__(
self.index: int | None = index

def set_location(self) -> None:
"""Set the location of this node based on the raw object. Not all objects have path
"""Set the location of this node based on the raw object. Not all objects have path.
:return:
"""
if self.raw_object and self.raw_object.get_ds():
Expand All @@ -98,7 +101,8 @@ def set_location(self) -> None:
)

def get_first_parent_matching_type(self, node_type: type) -> type:
"""Get the first parent of this node matching the given type
"""Get the first parent of this node matching the given type.
:param node_type: The type of the parent to get
:return:
"""
Expand Down Expand Up @@ -127,6 +131,7 @@ def __hash__(self):
def to_dict(self, **kwargs) -> dict:
"""Return a dictionary representation of this node. This representation is not meant to get the original object
back.
:return:
"""
data = {
Expand Down Expand Up @@ -163,7 +168,9 @@ def __init__(
index: int | None = None,
supported_compositions: list[str] | None = None,
) -> None:
""":param node_name:
"""Init a composite node.
:param node_name:
:param node_id:
:param raw_object: The raw ansible object matching this node in the graph. Will be None if there is no match on
Ansible side
Expand All @@ -184,14 +191,15 @@ def __init__(
self._node_counter = 0

def add_node(self, target_composition: str, node: Node) -> None:
"""Add a node in the target composition
"""Add a node in the target composition.
:param target_composition: The name of the target composition
:param node: The node to add in the given composition
:return:
"""
if target_composition not in self._supported_compositions:
msg = f"The target composition '{target_composition}' is unknown. Supported are: {self._supported_compositions}"
raise Exception(
raise ValueError(
msg,
)
self._compositions[target_composition].append(node)
Expand All @@ -200,7 +208,8 @@ def add_node(self, target_composition: str, node: Node) -> None:
self._node_counter += 1

def get_nodes(self, target_composition: str) -> list:
"""Get a node from the compositions
"""Get a node from the compositions.
:param target_composition:
:return: A list of the nodes.
"""
Expand All @@ -213,15 +222,17 @@ def get_nodes(self, target_composition: str) -> list:
return self._compositions[target_composition]

def get_all_tasks(self) -> list["TaskNode"]:
"""Return all the TaskNode inside this composite node
"""Return all the TaskNode inside this composite node.
:return:
"""
tasks: list[TaskNode] = []
self._get_all_tasks_nodes(tasks)
return tasks

def _get_all_tasks_nodes(self, task_acc: list["Node"]) -> None:
"""Recursively get all tasks
"""Recursively get all tasks.
:param task_acc:
:return:
"""
Expand All @@ -235,15 +246,17 @@ def _get_all_tasks_nodes(self, task_acc: list["Node"]) -> None:

def links_structure(self) -> dict[Node, list[Node]]:
"""Return a representation of the composite node where each key of the dictionary is the node and the
value is the list of the linked nodes
value is the list of the linked nodes.
:return:
"""
links: dict[Node, list[Node]] = defaultdict(list)
self._get_all_links(links)
return links

def _get_all_links(self, links: dict[Node, list[Node]]) -> None:
"""Recursively get the node links
"""Recursively get the node links.
:return:
"""
for nodes in self._compositions.values():
Expand All @@ -253,13 +266,15 @@ def _get_all_links(self, links: dict[Node, list[Node]]) -> None:
links[self].append(node)

def is_empty(self) -> bool:
"""Returns true if the composite node is empty, false otherwise
"""Return true if the composite node is empty, false otherwise.
:return:
"""
return all(len(nodes) <= 0 for _, nodes in self._compositions.items())

def has_node_type(self, node_type: type) -> bool:
"""Returns true if the composite node has at least one node of the given type, false otherwise
"""Return true if the composite node has at least one node of the given type, false otherwise.
:param node_type: The type of the node
:return:
"""
Expand All @@ -276,6 +291,7 @@ def has_node_type(self, node_type: type) -> bool:
def to_dict(self, **kwargs) -> dict:
"""Return a dictionary representation of this composite node. This representation is not meant to get the
original object back.
:return:
"""
node_dict = super().to_dict(**kwargs)
Expand Down Expand Up @@ -313,7 +329,8 @@ def __init__(
self._supported_compositions = ["tasks"]

def add_node(self, target_composition: str, node: Node) -> None:
"""Override the add_node because block only contains "tasks" regardless of the context (pre_tasks or post_tasks)
"""Override the add_node because block only contains "tasks" regardless of the context (pre_tasks or post_tasks).
:param target_composition: This is ignored. It's always "tasks" for block
:param node:
:return:
Expand All @@ -322,7 +339,8 @@ def add_node(self, target_composition: str, node: Node) -> None:

@property
def tasks(self) -> list[Node]:
"""The tasks attached to this block
"""The tasks attached to this block.
:return:
"""
return self.get_nodes("tasks")
Expand Down Expand Up @@ -365,7 +383,8 @@ def plays(
exclude_empty: bool = False,
exclude_without_roles: bool = False,
) -> list["PlayNode"]:
"""Return the list of plays
"""Return the list of plays.
:param exclude_empty: Whether to exclude the empty plays from the result or not
:param exclude_without_roles: Whether to exclude the plays that do not have roles
:return:
Expand All @@ -381,7 +400,8 @@ def plays(
return plays

def roles_usage(self) -> dict["RoleNode", set["PlayNode"]]:
"""For each role in the playbook, get the uniq plays that reference the role
"""For each role in the playbook, get the uniq plays that reference the role.
:return: A dict with key as role node and value the list of uniq plays that use it.
"""
usages = defaultdict(set)
Expand All @@ -405,7 +425,8 @@ def to_dict(
exclude_plays_without_roles: bool = False,
**kwargs,
) -> dict:
"""Return a dictionary representation of this playbook
"""Return a dictionary representation of this playbook.
:param exclude_empty_plays: Whether to exclude the empty plays from the result or not
:param exclude_plays_without_roles: Whether to exclude the plays that do not have roles
:param kwargs:
Expand Down Expand Up @@ -442,7 +463,9 @@ def __init__(
index: int | None = None,
hosts: list[str] | None = None,
) -> None:
""":param node_name:
"""
:param node_name:
:param node_id:
:param hosts: List of hosts attached to the play
"""
Expand All @@ -461,6 +484,7 @@ def __init__(
@property
def roles(self) -> list["RoleNode"]:
"""Return the roles of the plays. Tasks using "include_role" are NOT returned.
:return:
"""
return self.get_nodes("roles")
Expand All @@ -480,6 +504,7 @@ def tasks(self) -> list["Node"]:
def to_dict(self, **kwargs) -> dict:
"""Return a dictionary representation of this composite node. This representation is not meant to get the
original object back.
:return:
"""
data = super().to_dict(**kwargs)
Expand Down Expand Up @@ -523,7 +548,9 @@ def __init__(
parent: "Node" = None,
index: int | None = None,
) -> None:
""":param node_name:
"""
:param node_name:
:param node_id:
:param raw_object:
"""
Expand All @@ -550,7 +577,9 @@ def __init__(
index: int | None = None,
include_role: bool = False,
) -> None:
""":param node_name:
"""
:param node_name:
:param node_id:
:param raw_object:
"""
Expand All @@ -565,7 +594,8 @@ def __init__(
)

def set_location(self) -> None:
"""Retrieve the position depending on whether it's an include_role or not
"""Retrieve the position depending on whether it's an include_role or not.
:return:
"""
if self.raw_object and not self.include_role:
Expand All @@ -586,6 +616,7 @@ def has_loop(self) -> bool:
def to_dict(self, **kwargs) -> dict:
"""Return a dictionary representation of this composite node. This representation is not meant to get the
original object back.
:param kwargs:
:return:
"""
Expand Down
2 changes: 1 addition & 1 deletion ansibleplaybookgrapher/renderer/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def render(
open_protocol_handler: str,
open_protocol_custom_formats: dict[str, str],
output_filename: str,
view: bool,
view: bool = False,
hide_empty_plays: bool = False,
hide_plays_without_roles: bool = False,
**kwargs,
Expand Down
2 changes: 1 addition & 1 deletion ansibleplaybookgrapher/renderer/graphviz/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def render(
open_protocol_handler: str,
open_protocol_custom_formats: dict[str, str],
output_filename: str,
view: bool,
view: bool = False,
hide_empty_plays: bool = False,
hide_plays_without_roles: bool = False,
**kwargs,
Expand Down
18 changes: 12 additions & 6 deletions ansibleplaybookgrapher/renderer/json.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def render(
open_protocol_handler: str | None,
open_protocol_custom_formats: dict[str, str] | None,
output_filename: str,
view: bool,
view: bool = False,
hide_empty_plays: bool = False,
hide_plays_without_roles: bool = False,
**kwargs,
Expand Down Expand Up @@ -92,7 +92,9 @@ def build_playbook(
hide_plays_without_roles: bool = False,
**kwargs,
) -> str:
""":param hide_empty_plays:
"""Build a playbook.
:param hide_empty_plays:
:param hide_plays_without_roles:
:param kwargs:
:return:
Expand All @@ -109,7 +111,8 @@ def build_playbook(
return json.dumps(self.json_output)

def build_play(self, play_node: PlayNode, **kwargs) -> None:
"""Not needed
"""Not needed.
:param play_node:
:param kwargs:
:return:
Expand All @@ -122,7 +125,8 @@ def build_task(
fontcolor: str,
**kwargs,
) -> None:
"""Not needed
"""Not needed.
:param task_node:
:param color:
:param fontcolor:
Expand All @@ -137,7 +141,8 @@ def build_role(
fontcolor: str,
**kwargs,
) -> None:
"""Not needed
"""Not needed.
:param role_node:
:param color:
:param fontcolor:
Expand All @@ -152,7 +157,8 @@ def build_block(
fontcolor: str,
**kwargs,
) -> None:
"""Not needed
"""Not needed.
:param block_node:
:param color:
:param fontcolor:
Expand Down
Loading

0 comments on commit 44f06cb

Please sign in to comment.