feat: Add rendered images to job summary (#112)

This commit is contained in:
Mohamed El Mouctar Haidara 2022-10-17 15:46:07 +02:00 committed by GitHub
parent 4f3982ad5b
commit 3326ab0dde
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 116 additions and 21 deletions

View file

@ -8,9 +8,14 @@ on:
branches:
- main
permissions: write-all
jobs:
pytest:
name: Tests Py${{ matrix.python-version }} - Ansible ${{ matrix.ansible-version }}
env:
MATRIX_JOB_IDENTIFIER: py${{ matrix.python-version }}-ansible${{ matrix.ansible-version }}
SVG_FILES_PATH: tests/generated-svgs
runs-on: ubuntu-latest
strategy:
fail-fast: false
@ -19,9 +24,12 @@ jobs:
# See https://www.ansible.com/blog/ansible-3.0.0-qa and https://docs.ansible.com/ansible/devel/reference_appendices/release_and_maintenance.html
ansible-version: [ 2.12.9, 2.13.4 ]
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
ref: ${{ github.head_ref }}
- uses: actions/setup-python@v4
name: Setup Python ${{ matrix.python-version }}
@ -30,24 +38,43 @@ jobs:
- name: Install prereqs
run: |
pip install ansible-core==${{ matrix.ansible-version }} virtualenv setuptools wheel coveralls
pip install -r tests/requirements_tests.txt
pip install -q ansible-core==${{ matrix.ansible-version }} virtualenv setuptools wheel coveralls
pip install -qr tests/requirements_tests.txt
pip freeze
sudo apt-get install -y graphviz
sudo apt-get install -yq graphviz
ansible-galaxy install -r tests/fixtures/requirements.yml
- name: Pytest
env:
PY_COLORS: "1"
COMMIT_SHA: ${{ github.event.pull_request.head.sha || github.head_ref }}
run: make test
- name: Upload generated SVGs as artefacts
uses: actions/upload-artifact@v3
with:
name: generated-svgs-py${{ matrix.python-version }}-ansible${{ matrix.ansible-version }}
path: tests/generated_svg/
name: generated-svgs-${{ env.MATRIX_JOB_IDENTIFIER }}
path: ${{ env.SVG_FILES_PATH }}/
if-no-files-found: error # the tests should generate SVGs files
- uses: stefanzweifel/git-auto-commit-action@v4
id: commit-svg-files
with:
commit_message: Adding SVG for the run ${{ env.MATRIX_JOB_IDENTIFIER }}
file_pattern: ${{ env.SVG_FILES_PATH }}/*.svg
skip_dirty_check: true
add_options: '--force'
push_options: '--force'
branch: generated-svgs-${{ github.head_ref }}-${{ env.MATRIX_JOB_IDENTIFIER }}
create_branch: true
- name: Publish job summary
env:
SVG_COMMIT_SHA: ${{ steps.commit-svg-files.outputs.commit_hash }}
run: |
env
python tests/generate-job-summary.py >> $GITHUB_STEP_SUMMARY
- name: Test installation in virtualenv
run: make test_install ANSIBLE_VERSION=${{ matrix.ansible-version }}

2
.gitignore vendored
View file

@ -108,5 +108,5 @@ venv.bak/
.idea
.vagrant
Vagrantfile
generated_svg
generated-svgs
**/.DS_Store

View file

@ -27,6 +27,6 @@ test:
clean:
@echo "Cleaning..."
rm -rf ansible_playbook_grapher.egg-info build dist $(VIRTUALENV_DIR) tests/htmlcov tests/.pytest_cache .eggs tests/generated_svg tests/.coverage
rm -rf ansible_playbook_grapher.egg-info build dist $(VIRTUALENV_DIR) tests/htmlcov tests/.pytest_cache .eggs tests/generated-svgs tests/.coverage
.PHONY: clean test_install

View file

@ -26,9 +26,9 @@ JavaScript:
the files for the others nodes. The cursor will be at the task exact position in the file.
Lastly, you can provide your own protocol formats
with `--open-protocol-handler custom --open-protocol-custom-formats '{}'`. See the help
and [an example.](https://github.com/haidaraM/ansible-playbook-grapher/blob/12cee0fbd59ffbb706731460e301f0b886515357/ansibleplaybookgrapher/graphbuilder.py#L33-L42)
and [an example.](https://github.com/haidaraM/ansible-playbook-grapher/blob/12cee0fbd59ffbb706731460e301f0b886515357/ansibleplaybookgrapher/graphbuilder.py#L33-L42).
- Filer tasks based on tags
- Export the dot file using to generate the graph with Graphviz.
- Export the dot file used to generate the graph with Graphviz.
## Prerequisites
@ -110,9 +110,14 @@ optional arguments:
custom. You should provide a JSON formatted string
like: {"file": "", "folder": ""}. Example: If you want
to open folders (roles) inside the browser and files
(tasks) in vscode, set this to '{"file":
(tasks) in vscode, set it to: '{"file":
"vscode://file/{path}:{line}:{column}", "folder":
"{path}"}'
"{path}"}'. path: the absolute path to the file
containing the the plays/tasks/roles. line/column: the
position of the plays/tasks/roles in the file. You can
optionally add the attribute "remove_from_path" to
remove some parts of the path if you want relative
paths.
--open-protocol-handler {default,vscode,custom}
The protocol to use to open the nodes when double-
clicking on them in your SVG viewer. Your SVG viewer
@ -145,8 +150,11 @@ optional arguments:
<playbook>.svg
-s, --save-dot-file Save the dot file used to generate the graph.
-t TAGS, --tags TAGS only run plays and tasks tagged with these values
-v, --verbose verbose mode (-vvv for more, -vvvv to enable
connection debugging)
-v, --verbose Causes Ansible to print more debug messages. Adding
multiple -v will increase the verbosity, the builtin
plugins currently evaluate up to -vvvvvv. A reasonable
level to start is -vvv, connection debugging might
require -vvvv.
```
@ -169,8 +177,8 @@ More information [here](https://docs.ansible.com/ansible/latest/reference_append
arguments may not appear in the graph.
- The rendered SVG graph may sometime display tasks in a wrong order. I cannot control this behavior of Graphviz yet.
Always check the edge label to know the tasks order.
- The label edge may overlap with each other. The edge labels are positioned so that they are as close as possible to
the target nodes. If a single role is used in multiple plays or playbooks, this can happen.
- The label of the edges may overlap with each other. They are positioned so that they are as close as possible to
the target nodes. If the same role is used in multiple plays or playbooks, the labels can overlap.
## Contribution
@ -190,7 +198,7 @@ export TEST_VIEW_GENERATED_FILE=1
$ make test # run all tests
```
The graphs are generated in the folder `tests/generated_svg`. They are also generated as artefacts
The graphs are generated in the folder `tests/generated-svgs`. They are also generated as artefacts
in [Github Actions](https://github.com/haidaraM/ansible-playbook-grapher/actions). Feel free to look at them when
submitting PRs.

View file

@ -160,8 +160,12 @@ class PlaybookGrapherCLI(CLI):
--open-protocol-handler is set to custom.
You should provide a JSON formatted string like: {"file": "", "folder": ""}.
Example: If you want to open folders (roles) inside the browser and files (tasks) in
vscode, set this to
'{"file": "vscode://file/{path}:{line}:{column}", "folder": "{path}"}'
vscode, set it to:
'{"file": "vscode://file/{path}:{line}:{column}", "folder": "{path}"}'.
path: the absolute path to the file containing the the plays/tasks/roles.
line/column: the position of the plays/tasks/roles in the file.
You can optionally add the attribute "remove_from_path" to remove some parts of the
path if you want relative paths.
""",
)

View file

@ -12,7 +12,7 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from typing import Dict, Optional, Tuple, List, Set
from typing import Dict, Optional, Tuple, List
from ansible.utils.display import Display
from graphviz import Digraph
@ -471,8 +471,11 @@ class GraphvizGraphBuilder:
:return:
"""
if node.path:
remove_from_path = self.open_protocol_formats.get("remove_from_path", "")
path = node.path.replace(remove_from_path, "")
url = self.open_protocol_formats[node_type].format(
path=node.path, line=node.line, column=node.column
path=path, line=node.line, column=node.column
)
display.vvvv(f"Open protocol URL for node {node}: {url}")
return url

View file

@ -0,0 +1,30 @@
import glob
import os
from typing import List
from jinja2 import Template
DIR_PATH = os.path.dirname(os.path.realpath(__file__))
def list_svg_files(path_pattern: str) -> List[str]:
"""
:param path_pattern:
:return:
"""
return glob.glob(path_pattern)
if __name__ == "__main__":
with open(os.path.join(DIR_PATH, "job-summary.md.j2")) as template_file:
template = Template(template_file.read())
svg_files = list_svg_files(f"{os.environ['SVG_FILES_PATH']}/*.svg")
links = []
for f in svg_files:
links.append(
f"https://raw.githubusercontent.com/{os.environ['GITHUB_REPOSITORY']}/{os.environ['SVG_COMMIT_SHA']}/{f}"
)
print(template.render(svg_files=links))

6
tests/job-summary.md.j2 Normal file
View file

@ -0,0 +1,6 @@
### Generated SVG files
| Images |
|:-------:|
{% for svg_file in svg_files -%}
| ![svg]({{ svg_file }}) |
{% endfor %}

View file

@ -1,3 +1,4 @@
import json
import os
from _elementtree import Element
from typing import Dict, List, Tuple
@ -32,6 +33,22 @@ def run_grapher(
if os.environ.get("TEST_VIEW_GENERATED_FILE") == "1":
additional_args.insert(0, "--view")
if os.environ.get("GITHUB_ACTIONS") == "true":
# Setting a custom protocol handler for browsing on github
additional_args.insert(0, "--open-protocol-handler")
additional_args.insert(1, "custom")
repo = os.environ["GITHUB_REPOSITORY"]
commit_sha = os.environ["COMMIT_SHA"]
formats = {
"file": f"https://github.com/{repo}/blob/{commit_sha}" + "/{path}#L{line}",
"folder": f"https://github.com/{repo}/tree/{commit_sha}" + "/{path}",
"remove_from_path": os.environ["GITHUB_WORKSPACE"],
}
additional_args.insert(2, "--open-protocol-custom-formats")
additional_args.insert(3, json.dumps(formats))
if "--open-protocol-handler" not in additional_args:
additional_args.insert(0, "--open-protocol-handler")
additional_args.insert(1, "vscode")
@ -42,7 +59,7 @@ def run_grapher(
if output_filename: # the default filename is the playbook file name minus .yml
# put the generated svg in a dedicated folder
output_filename = output_filename.replace("[", "-").replace("]", "")
args.extend(["-o", os.path.join(DIR_PATH, "generated_svg", output_filename)])
args.extend(["-o", os.path.join(DIR_PATH, "generated-svgs", output_filename)])
args.extend(additional_args)