diff --git a/README.md b/README.md index e906b353..daa0be8c 100644 --- a/README.md +++ b/README.md @@ -48,10 +48,20 @@ for the supported Ansible version. ## Installation -```shell script +```shell pip install ansible-playbook-grapher ``` +You can also install the unpublished version from GitHub direction. Examples: + +```shell +# Install the version from the main branch +pip install "ansible-playbook-grapher @ git+https://github.com/haidaraM/ansible-playbook-grapher" + +# Install the version from a specific branch +pip install "ansible-playbook-grapher @ git+https://github.com/haidaraM/ansible-playbook-grapher@specific-branch" +``` + ### Renderers At the time of writing, two renderers are supported: diff --git a/ansibleplaybookgrapher/__init__.py b/ansibleplaybookgrapher/__init__.py index ccd20efa..20c62ea2 100644 --- a/ansibleplaybookgrapher/__init__.py +++ b/ansibleplaybookgrapher/__init__.py @@ -1,77 +1,2 @@ -# Copyright (C) 2023 Mohamed El Mouctar HAIDARA -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from typing import Dict, List, Set, Tuple - -from ansible.utils.display import Display - -from ansibleplaybookgrapher.graph_model import ( - PlaybookNode, - RoleNode, - PlayNode, -) -from ansibleplaybookgrapher.parser import PlaybookParser -from ansibleplaybookgrapher.utils import merge_dicts -from .graph_model import PlaybookNode, PlayNode, TaskNode, RoleNode, BlockNode -from .parser import PlaybookParser - -__version__ = "2.1.2" +__version__ = "2.2.0.dev0" __prog__ = "ansible-playbook-grapher" - -display = Display() - - -class Grapher: - def __init__(self, playbook_filenames: List[str]): - """ - :param playbook_filenames: List of playbooks to graph - """ - self.playbook_filenames = playbook_filenames - - def parse( - self, - include_role_tasks: bool = False, - tags: List[str] = None, - skip_tags: List[str] = None, - group_roles_by_name: bool = False, - ) -> Tuple[List[PlaybookNode], Dict[RoleNode, Set[PlayNode]]]: - """ - Parses all the provided playbooks - :param include_role_tasks: Should we include the role tasks - :param tags: Only add plays and tasks tagged with these values - :param skip_tags: Only add plays and tasks whose tags do not match these values - :param group_roles_by_name: Group roles by name instead of considering them as separate nodes with different IDs - :return: Tuple of the list of playbook nodes and the dictionary of the role usages: the key is the role and the - value is the set of plays that use the role. - """ - playbook_nodes = [] - roles_usage: Dict[RoleNode, Set[PlayNode]] = {} - - for playbook_file in self.playbook_filenames: - display.display(f"Parsing playbook {playbook_file}") - playbook_parser = PlaybookParser( - playbook_filename=playbook_file, - tags=tags, - skip_tags=skip_tags, - include_role_tasks=include_role_tasks, - group_roles_by_name=group_roles_by_name, - ) - playbook_node = playbook_parser.parse() - playbook_nodes.append(playbook_node) - - # Update the usage of the roles - roles_usage = merge_dicts(roles_usage, playbook_node.roles_usage()) - - return playbook_nodes, roles_usage diff --git a/ansibleplaybookgrapher/cli.py b/ansibleplaybookgrapher/cli.py index acef4571..b6d9d515 100644 --- a/ansibleplaybookgrapher/cli.py +++ b/ansibleplaybookgrapher/cli.py @@ -1,4 +1,4 @@ -# Copyright (C) 2023 Mohamed El Mouctar HAIDARA +# Copyright (C) 2024 Mohamed El Mouctar HAIDARA # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -23,7 +23,8 @@ from ansible.release import __version__ as ansible_version from ansible.utils.display import Display -from ansibleplaybookgrapher import __prog__, __version__, Grapher +from ansibleplaybookgrapher.grapher import Grapher +from ansibleplaybookgrapher import __prog__, __version__ from ansibleplaybookgrapher.renderer import OPEN_PROTOCOL_HANDLERS from ansibleplaybookgrapher.renderer.graphviz import GraphvizRenderer from ansibleplaybookgrapher.renderer.mermaid import ( diff --git a/ansibleplaybookgrapher/grapher.py b/ansibleplaybookgrapher/grapher.py new file mode 100644 index 00000000..81967798 --- /dev/null +++ b/ansibleplaybookgrapher/grapher.py @@ -0,0 +1,67 @@ +# Copyright (C) 2024 Mohamed El Mouctar HAIDARA +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from typing import Dict, List, Set, Tuple + +from ansibleplaybookgrapher.graph_model import ( + PlaybookNode, + RoleNode, + PlayNode, +) +from ansibleplaybookgrapher.parser import PlaybookParser +from ansibleplaybookgrapher.utils import merge_dicts + + +class Grapher: + def __init__(self, playbook_filenames: List[str]): + """ + :param playbook_filenames: List of playbooks to graph + """ + self.playbook_filenames = playbook_filenames + + def parse( + self, + include_role_tasks: bool = False, + tags: List[str] = None, + skip_tags: List[str] = None, + group_roles_by_name: bool = False, + ) -> Tuple[List[PlaybookNode], Dict[RoleNode, Set[PlayNode]]]: + """ + Parses all the provided playbooks + :param include_role_tasks: Should we include the role tasks + :param tags: Only add plays and tasks tagged with these values + :param skip_tags: Only add plays and tasks whose tags do not match these values + :param group_roles_by_name: Group roles by name instead of considering them as separate nodes with different IDs + :return: Tuple of the list of playbook nodes and the dictionary of the role usages: the key is the role and the + value is the set of plays that use the role. + """ + playbook_nodes = [] + roles_usage: Dict[RoleNode, Set[PlayNode]] = {} + + for playbook_file in self.playbook_filenames: + playbook_parser = PlaybookParser( + playbook_filename=playbook_file, + tags=tags, + skip_tags=skip_tags, + include_role_tasks=include_role_tasks, + group_roles_by_name=group_roles_by_name, + ) + playbook_node = playbook_parser.parse() + playbook_nodes.append(playbook_node) + + # Update the usage of the roles + roles_usage = merge_dicts(roles_usage, playbook_node.roles_usage()) + + return playbook_nodes, roles_usage diff --git a/ansibleplaybookgrapher/parser.py b/ansibleplaybookgrapher/parser.py index 6a8779b5..97763596 100644 --- a/ansibleplaybookgrapher/parser.py +++ b/ansibleplaybookgrapher/parser.py @@ -1,4 +1,4 @@ -# Copyright (C) 2023 Mohamed El Mouctar HAIDARA +# Copyright (C) 2024 Mohamed El Mouctar HAIDARA # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -167,7 +167,7 @@ def parse(self, *args, **kwargs) -> PlaybookNode: add post_tasks :return: """ - + display.display(f"Parsing playbook {self.playbook_filename}") playbook = Playbook.load( self.playbook_filename, loader=self.data_loader, diff --git a/ansibleplaybookgrapher/renderer/mermaid.py b/ansibleplaybookgrapher/renderer/mermaid.py index fb208c87..677de1ae 100644 --- a/ansibleplaybookgrapher/renderer/mermaid.py +++ b/ansibleplaybookgrapher/renderer/mermaid.py @@ -18,7 +18,13 @@ from ansible.utils.display import Display -from ansibleplaybookgrapher import BlockNode, RoleNode, TaskNode, PlayNode, PlaybookNode +from ansibleplaybookgrapher.graph_model import ( + BlockNode, + RoleNode, + TaskNode, + PlayNode, + PlaybookNode, +) from ansibleplaybookgrapher.renderer import PlaybookBuilder, Renderer display = Display() diff --git a/setup.cfg b/setup.cfg index 5424cc26..6b947792 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [metadata] -description-file = Readme.md +description_file = Readme.md [bdist_wheel] universal = 1 diff --git a/tests/test_parser.py b/tests/test_parser.py index 3f6b6a0f..80d4d9ab 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -4,7 +4,7 @@ import pytest from ansible.utils.display import Display -from ansibleplaybookgrapher import PlaybookParser +from ansibleplaybookgrapher.parser import PlaybookParser from ansibleplaybookgrapher.cli import PlaybookGrapherCLI from ansibleplaybookgrapher.graph_model import ( TaskNode,