diff --git a/custom_json_diff/bom_diff_template.j2 b/custom_json_diff/bom_diff_template.j2 index dd90580..e4039e0 100644 --- a/custom_json_diff/bom_diff_template.j2 +++ b/custom_json_diff/bom_diff_template.j2 @@ -11,12 +11,7 @@ .table_summary2 { display: grid; - grid-template-columns: 72% 23% 5%; - } - - .table_summary3 { - display: grid; - grid-template-columns: 30% 40% 30%; + grid-template-columns: 25% 23% 2% 25% 25%; } th, td { @@ -29,6 +24,7 @@ +

BOM Diff Summary

@@ -36,8 +32,7 @@ - Overall - Summary + Common Elements Summary {% for item in stats["common_summary"] %} @@ -59,8 +54,32 @@
+
+
+ + + + + + + + + + {% for key, value in stats["breakdown"]|items %} + + + + + + {% endfor %} +
+ Unique Elements Breakdown +
{{ bom_1 }}{{ bom_2 }}
{{ key }}{{ value[0] }}{{ value[1] }}
+
+
-

BOM Diff Summary

+
@@ -84,15 +103,24 @@ {% endif %} {% if diff_apps_1 or diff_apps_2 %} - applications + applications

{{ diff_apps_1 | length }} + vs {{ diff_apps_2 | length }} {% for item in diff_apps_1 %}
{{ item['name'] }}@{{ item['version'] }}
    {% for key, value in item|items %} - {% if value != "" and key not in ["properties","evidence","hashes","licenses"] %} + {% if value != "" and key not in ["properties","evidence","hashes","licenses","externalReferences"] %}
  • {{ key }}: {{ value }}
  • {% endif %} + {% if key in ["properties","hashes","licenses","externalReferences"] and value|length > 0 %} +
  • {{ key }}:
  • +
      + {% for i in value %} +
    • {{ i }}
    • + {% endfor %} +
    + {% endif %} {% endfor %}
@@ -102,9 +130,17 @@ {{ item['name'] }}@{{ item['version'] }} @@ -113,15 +149,28 @@ {% endif %} {% if diff_frameworks_1 or diff_frameworks_2 %} - frameworks + frameworks

{{ diff_frameworks_1 | length }} + vs {{ diff_frameworks_2 | length }} {% for item in diff_frameworks_1 %}
{{ item['name'] }}@{{ item['version'] }}
    {% for key, value in item|items %} - {% if value != "" and key not in ["properties","evidence","hashes","licenses"] %} + {% if value != "" and key not in ["properties","evidence","hashes","licenses","externalReferences"] %}
  • {{ key }}: {{ value }}
  • {% endif %} + {% if key in ["properties","hashes","licenses","externalReferences"] and value|length > 0 %} +
  • +
    + {{ key }}: +
      + {% for i in value %} +
    • {{ i }}
    • + {% endfor %} +
    +
    +
  • + {% endif %} {% endfor %}
@@ -131,9 +180,21 @@ {{ item['name'] }}@{{ item['version'] }} @@ -142,7 +203,8 @@ {% endif %} {% if diff_lib_1 or diff_lib_2 %} - libraries + libraries

{{ diff_lib_1 | length }} vs {{ diff_lib_2 | length }} + {% for item in diff_lib_1 %}
{{ item['name'] }}@{{ item['version'] }} @@ -151,7 +213,18 @@ {% if value != "" and key not in ["hashes", "licenses", "properties", "evidence"] %}
  • {{ key }}: {{ value }}
  • {% endif %} - + {% if key in ["properties","hashes","licenses","externalReferences"] and value|length > 0 %} +
  • +
    + {{ key }}: +
      + {% for i in value %} +
    • {{ i }}
    • + {% endfor %} +
    +
    +
  • + {% endif %} {% endfor %}
    @@ -161,9 +234,21 @@ {{ item['name'] }}@{{ item['version'] }} @@ -172,15 +257,28 @@ {% endif %} {% if diff_other_1 or diff_other_2 %} - other types + other
    components

    {{ diff_other_1 | length }} + vs {{ diff_other_2 | length }} {% for item in diff_other_1 %}
    {{ item['name'] }}@{{ item['version'] }}
      {% for key, value in item|items %} - {% if value != "" and key not in ["properties","evidence","hashes","licenses"] %} + {% if value != "" and key not in ["properties","evidence","hashes","licenses","externalReferences"] %}
    • {{ key }}: {{ value }}
    • {% endif %} + {% if key in ["properties","hashes","licenses","externalReferences"] and value|length > 0 %} +
    • +
      + {{ key }}: +
        + {% for i in value %} +
      • {{ i }}
      • + {% endfor %} +
      +
      +
    • + {% endif %} {% endfor %}
    @@ -190,9 +288,21 @@ {{ item['name'] }}@{{ item['version'] }} @@ -202,13 +312,14 @@ {% if not comp_only %} {% if diff_services_1 or diff_services_2 %} - services + services

    {{ diff_services_1 | length }} + vs {{ diff_services_2 | length }} {% for item in diff_services_1 %}
    {{ item['name'] }}
      {% for key, value in item|items %} - {% if value != "" and key not in ["properties","evidence","hashes","licenses"] %} + {% if value != "" %}
    • {{ key }}: {{ value }}
    • {% endif %} {% endfor %} @@ -220,7 +331,7 @@ {{ item['name'] }}
        {% for key, value in item|items %} - {% if value != "" and key not in ["properties","evidence","hashes","licenses"] %} + {% if value != "" %}
      • {{ key }}: {{ value }}
      • {% endif %} {% endfor %} @@ -231,7 +342,8 @@ {% endif %} {% if diff_deps_1 or diff_deps_2 %} - dependencies + dependencies

        {{ diff_deps_1 | length }} + vs {{ diff_deps_2 | length }} {% for item in diff_deps_1 %}
        {{ item['short_ref'] }} @@ -278,7 +390,7 @@
    -

    +
    @@ -303,9 +415,21 @@ {{ item['name'] }}@{{ item['version'] }} @@ -320,9 +444,21 @@ {{ item['name'] }}@{{ item['version'] }} @@ -337,9 +473,21 @@ {{ item['name'] }}@{{ item['version'] }} @@ -355,9 +503,21 @@ {{ item['name'] }}@{{ item['version'] }} @@ -373,7 +533,7 @@ {{ item['name'] }}
    -

    -
    -
    -
    - - - - - - - - - - {% for key, value in stats["breakdown"]|items %} - - - - - - {% endfor %} - - - -
    - Matched Components Breakdown -
    {{ bom_1 }}{{ bom_2 }}
    {{ key }}{{ value[0] }}{{ value[1] }}
    -
    -
    -
    -

    +
    \ No newline at end of file diff --git a/custom_json_diff/custom_diff.py b/custom_json_diff/custom_diff.py index 399e8a0..76085af 100644 --- a/custom_json_diff/custom_diff.py +++ b/custom_json_diff/custom_diff.py @@ -22,25 +22,14 @@ def calculate_pcts(diffs: Dict, j1: BomDicts, j2: BomDicts) -> Dict: result = [] for key, value in common_counts.items(): total = j1_counts[key] + j2_counts[key] - if not total == 0: + if total != 0: result.append([f"Common {key} matched: ", f"{value} ({round(((value*2)/total) * 100, 2)})%"]) - result_2 = summarize_diffs({}, generate_counts(diffs["diff_summary"][j1.filename]), j1_counts) - result_2 = summarize_diffs(result_2, generate_counts(diffs["diff_summary"][j2.filename]), j2_counts) + result_2 = summarize_diffs({}, generate_counts(diffs["diff_summary"][j1.filename]), j1_counts, common_counts) + result_2 = summarize_diffs(result_2, generate_counts(diffs["diff_summary"][j2.filename]), j2_counts, common_counts) return {"common_summary": result, "breakdown": result_2} -def summarize_diffs(result: Dict, diff_counts: Dict, bom_counts: Dict) -> Dict: - for key, value in diff_counts.items(): - found = bom_counts[key] - value - if not bom_counts[key] == 0: - if result.get(key): - result[key].append(f"{found}/{bom_counts[key]} ({round(((found) / bom_counts[key]) * 100, 2)}%)") - else: - result[key] = [f"{found}/{bom_counts[key]} ({round(((found) / bom_counts[key]) * 100, 2)}%)"] - return result - - def check_regex(regex_keys: Set[re.Pattern], key: str) -> bool: return any(regex.match(key) for regex in regex_keys) @@ -119,14 +108,11 @@ def filter_dict(data: Dict, options: Options) -> FlatDicts: def generate_counts(data: Dict) -> Dict: - result = {"libraries": len(data.get("components", {}).get("libraries", [])), - "frameworks": len(data.get("components", {}).get("frameworks", [])), - "applications": len(data.get("components", {}).get("applications", [])), - "other_components": len(data.get("components", {}).get("other_components", []))} - result["components"] = sum(result.values()) - result |= {"services": len(data.get("services", [])), - "dependencies": len(data.get("dependencies", []))} - return result + return {"libraries": len(data.get("components", {}).get("libraries", [])), + "frameworks": len(data.get("components", {}).get("frameworks", [])), + "applications": len(data.get("components", {}).get("applications", [])), + "other_components": len(data.get("components", {}).get("other_components", [])), + "services": len(data.get("services", [])), "dependencies": len(data.get("dependencies", []))} def get_diff(j1: FlatDicts, j2: FlatDicts, options: Options) -> Dict: @@ -213,3 +199,14 @@ def sort_list(lst: List, sort_keys: List[str]) -> List: if isinstance(lst[0], (str, int)): lst.sort() return lst + + +def summarize_diffs(result: Dict, diff_counts: Dict, bom_counts: Dict, common_counts: Dict) -> Dict: + for key, value in diff_counts.items(): + if bom_counts[key] != 0: + found = bom_counts[key] - common_counts.get(key, 0) + if result.get(key): + result[key].append(f"{found}/{bom_counts[key]} ({round((found / bom_counts[key]) * 100, 2)}%)") + else: + result[key] = [f"{found}/{bom_counts[key]} ({round((found / bom_counts[key]) * 100, 2)}%)"] + return result diff --git a/custom_json_diff/custom_diff_classes.py b/custom_json_diff/custom_diff_classes.py index 46cd2b6..735d4f7 100644 --- a/custom_json_diff/custom_diff_classes.py +++ b/custom_json_diff/custom_diff_classes.py @@ -161,18 +161,16 @@ def generate_counts(self) -> Dict: def to_summary(self) -> Dict: summary: Dict = {self.filename: {}} if self.components: - summary[self.filename] = { - "components": { - "libraries": [ - i.original_data for i in self.components if i.component_type == "library"], - "frameworks": [ - i.original_data for i in self.components if i.component_type == "framework"], - "applications": [i.original_data for i in self.components if + summary[self.filename] = {"components": { + "libraries": [i.original_data for i in self.components if + i.component_type == "library"], + "frameworks": [i.original_data for i in self.components if + i.component_type == "framework"], + "applications": [i.original_data for i in self.components if i.component_type == "application"], - "other_components": [i.original_data for i in self.components if - i.component_type not in ("library", "framework", "application")], - } - } + "other_components": [i.original_data for i in self.components if + i.component_type not in ( + "library", "framework", "application")], }} if not self.options.comp_only: if self.data: summary[self.filename] |= {"misc_data": self.data.to_dict(unflat=True)}