From 13837784e317d905feeaf9cb5fd063109122e273 Mon Sep 17 00:00:00 2001 From: David Moreau Simard Date: Mon, 22 Jun 2020 19:44:40 -0400 Subject: [PATCH] ui: Improve display for result diffs Fixes: https://github.com/ansible-community/ara/issues/29 Change-Id: Id4442f0f9c4dcb5520f63970bb9fb17a03d5ec0d --- ara/ui/templates/result.html | 7 +++- ara/ui/templatetags/diff_result.py | 61 ++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 ara/ui/templatetags/diff_result.py diff --git a/ara/ui/templates/result.html b/ara/ui/templates/result.html index 9eada4f2..058ab496 100644 --- a/ara/ui/templates/result.html +++ b/ara/ui/templates/result.html @@ -3,6 +3,7 @@ {% include "partials/playbook_card.html" with playbook=result.playbook %} {% load pygments_highlights %} {% load datetime_formatting %} +{% load diff_result %}
@@ -35,7 +36,11 @@ {{ field }} - {{ value | format_data | safe }} + {% if field == "diff" %} + {{ value | diff_result | format_data | safe }} + {% else %} + {{ value | format_data | safe }} + {% endif %} {% endfor %} diff --git a/ara/ui/templatetags/diff_result.py b/ara/ui/templatetags/diff_result.py new file mode 100644 index 00000000..544e7206 --- /dev/null +++ b/ara/ui/templatetags/diff_result.py @@ -0,0 +1,61 @@ +# Copyright (c) 2020 The ARA Records Ansible authors +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +import difflib +import json + +from django import template + +register = template.Library() + + +def render_diff(before="", after="", before_header="before", after_header="after"): + """ + Renders a diff provided by Ansible task results + """ + # fmt: off + # Some modules, such as file, might provide a diff in a dict format + if isinstance(before, dict) and isinstance(after, dict): + return difflib.unified_diff( + json.dumps(before, indent=4).splitlines(), + json.dumps(after, indent=4).splitlines(), + fromfile=before_header, + tofile=after_header + ) + else: + return difflib.unified_diff( + before.splitlines(), + after.splitlines(), + fromfile=before_header, + tofile=after_header + ) + # fmt: on + + +@register.filter(name="diff_result") +def diff_result(diff): + """ + Renders a diff (or a list of diffs) provided by Ansible task results + """ + diffs = [] + + # Modules are free to provide their own diff key which might not respect the convention set by modules such + # as "file", "ini_file", "lineinfile, "template" or "copy" causing a parsing failure. + # If that happens, give up and return value as it was provided so we don't raise an + # exception/internal server error. + try: + if isinstance(diff, list): + diffs = [render_diff(**result) for result in diff] + elif isinstance(diff, dict): + diffs = [render_diff(**diff)] + except (TypeError, AttributeError): + return diff + + # The unified diff is a generator, we need to iterate through it to return + # the entire diff. + lines = [] + for d in diffs: + for line in d: + lines.append(line) + + return "\n".join(lines)