diff --git a/src/formattedcode/output_html.py b/src/formattedcode/output_html.py index a2c236b2adb..1b2db9026ad 100644 --- a/src/formattedcode/output_html.py +++ b/src/formattedcode/output_html.py @@ -83,12 +83,16 @@ def process_codebase(self, codebase, html, **kwargs): license_references = [] if hasattr(codebase.attributes, 'license_references'): license_references = codebase.attributes.license_references + summary = None + if hasattr(codebase.attributes, 'summary'): + summary = codebase.attributes.summary template_loc = join(TEMPLATES_DIR, 'html', 'template.html') output_file = html write_templated( output_file=output_file, results=results, license_references=license_references, + summary=summary, version=version, template_loc=template_loc, ) @@ -133,18 +137,22 @@ def process_codebase(self, codebase, custom_output, custom_template, **kwargs): license_references = [] if hasattr(codebase.attributes, 'license_references'): license_references = codebase.attributes.license_references + summary = None + if hasattr(codebase.attributes, 'summary'): + summary = codebase.attributes.summary template_loc = custom_template output_file = custom_output write_templated( output_file=output_file, results=results, license_references=license_references, + summary=summary, version=version, template_loc=template_loc ) -def write_templated(output_file, results, license_references, version, template_loc): +def write_templated(output_file, results, license_references, summary, version, template_loc): """ Write scan output `results` to the `output_file` opened file using a template file at `template_loc`. @@ -155,6 +163,7 @@ def write_templated(output_file, results, license_references, version, template_ for template_chunk in generate_output( results=results, license_references=license_references, + summary=summary, version=version, template=template, ): @@ -184,7 +193,7 @@ def get_template(location): return env.get_template(template_name) -def generate_output(results, license_references, version, template): +def generate_output(results, license_references, summary, version, template): """ Yield unicode strings from incrementally rendering `results` and `version` with the Jinja `template` object. @@ -223,12 +232,20 @@ def generate_output(results, license_references, version, template): if TRACE: logger_debug(f"match: {match}") license_expression = match['license_expression'] - results.append({ + match_data = { 'start': match['start_line'], 'end': match['end_line'], 'what': 'license', 'value': license_expression, - }) + } + + if 'matched_text' in match: + match_data['matched_text'] = match['matched_text'] + + if 'matched_text_diagnostics' in match: + match_data['matched_text_diagnostics'] = match['matched_text_diagnostics'] + + results.append(match_data) if not license_references and license_expression not in licenses: license_object = get_licenses_db().get(license_expression) @@ -261,7 +278,7 @@ def generate_output(results, license_references, version, template): 'package_data': converted_packages } - return template.generate(files=files, license_references=license_references, version=version) + return template.generate(files=files, license_references=license_references, summary=summary, version=version) @output_impl diff --git a/src/formattedcode/templates/html/template.html b/src/formattedcode/templates/html/template.html index 894408f6503..e29b0b7d9ac 100644 --- a/src/formattedcode/templates/html/template.html +++ b/src/formattedcode/templates/html/template.html @@ -46,9 +46,101 @@ font-weight: normal; font-size: 12px; } + details { + margin: 5px 0; + } + summary { + cursor: pointer; + color: #5E81B7; + font-weight: bold; + } + summary:hover { + text-decoration: underline; + } + pre { + background: #f5f5f5; + padding: 10px; + border: 1px solid #ddd; + overflow-x: auto; + font-family: monospace; + font-size: 11px; + white-space: pre-wrap; + word-wrap: break-word; + } + .summary-section { + background: #f0f8ff; + padding: 15px; + margin-bottom: 20px; + border-left: 4px solid #5E81B7; + } + .summary-section h3 { + margin-top: 0; + color: #5E81B7; + font-size: 16px; + } + .summary-section p { + margin: 5px 0; + } + {% if summary %} +
+

Scan Summary

+ {% if summary.declared_license_expression %} +

Declared License: {{ summary.declared_license_expression }}

+ {% endif %} + {% if summary.declared_holder %} +

Declared Holder: {{ summary.declared_holder }}

+ {% endif %} + {% if summary.primary_language %} +

Primary Language: {{ summary.primary_language }}

+ {% endif %} + {% if summary.other_license_expressions %} +

Other License Expressions:

+ + {% endif %} + {% if summary.other_holders %} +

Other Holders:

+ + {% endif %} +
+ {% endif %} + {% if summary and summary.license_clarity_score %} + + + + + + + + + + + + + + + + + + + + + + + + +
License Clarity Score
Overall ScoreDeclared LicenseIdentification PrecisionHas License TextDeclared CopyrightsAmbiguous CompoundConflicting Categories
{{ summary.license_clarity_score.score }}{{ summary.license_clarity_score.declared_license }}{{ summary.license_clarity_score.identification_precision }}{{ summary.license_clarity_score.has_license_text }}{{ summary.license_clarity_score.declared_copyrights }}{{ summary.license_clarity_score.ambiguous_compound_licensing }}{{ summary.license_clarity_score.conflicting_license_categories }}
+ {% endif %} {% if files.license_copyright %} @@ -59,6 +151,7 @@ + @@ -71,8 +164,26 @@ {% if row.what == 'license' %} + {% else %} + {% endif %} {% endfor %} diff --git a/tests/formattedcode/test_output_templated.py b/tests/formattedcode/test_output_templated.py index 303bb97bb83..458dd373db9 100644 --- a/tests/formattedcode/test_output_templated.py +++ b/tests/formattedcode/test_output_templated.py @@ -72,6 +72,46 @@ def test_paths_are_posix_in_html_format_output(): assert '/copyright_acme_c-c.c' in results assert __version__ in results +@pytest.mark.scanslow +def test_html_output_includes_license_text(): + test_file = test_env.get_test_loc('templated/simple-license.txt') + result_file = test_env.get_temp_file('html') + run_scan_click(['--license', '--license-text', test_file, '--html', result_file]) + results = open(result_file).read() + assert 'matched text' in results.lower() + assert '
' in results  # Check for formatted text display
+    assert __version__ in results
+
+@pytest.mark.scanslow
+def test_html_output_includes_license_text_diagnostics():
+    test_file = test_env.get_test_loc('templated/simple-license.txt')
+    result_file = test_env.get_temp_file('html')
+    run_scan_click(['--license', '--license-text', '--license-text-diagnostics', 
+                    test_file, '--html', result_file])
+    results = open(result_file).read()
+    assert 'diagnostics' in results.lower()
+    assert __version__ in results
+
+@pytest.mark.scanslow
+def test_html_output_includes_license_clarity_score():
+    test_dir = test_env.get_test_loc('templated/simple')
+    result_file = test_env.get_temp_file('html')
+    run_scan_click(['--license', '--classify', '--license-clarity-score', 
+                    test_dir, '--html', result_file])
+    results = open(result_file).read()
+    assert 'License Clarity Score' in results
+    assert 'score' in results.lower()
+    assert __version__ in results
+
+@pytest.mark.scanslow
+def test_html_output_includes_summary():
+    test_dir = test_env.get_test_loc('templated/simple')
+    result_file = test_env.get_temp_file('html')
+    run_scan_click(['--license', '--classify', '--summary', 
+                    test_dir, '--html', result_file])
+    results = open(result_file).read()
+    assert 'Scan Summary' in results
+    assert __version__ in results
 
 @pytest.mark.scanslow
 def test_scanned_path_is_present_in_html_app_output():
@@ -104,6 +144,7 @@ def test_scan_html_output_does_not_truncate_copyright_html():
           
+ '''
Copyrights and Licenses Information
end what valuematched text/ diagnostics
{{ row.what }}{{ row.value }} + {% if row.matched_text %} +
+ View Matched Text +
{{ row.matched_text|escape }}
+
+ {% endif %} + {% if row.matched_text_diagnostics %} +
+ View Diagnostics +
{{ row.matched_text_diagnostics|escape }}
+
+ {% endif %} + {% if not row.matched_text and not row.matched_text_diagnostics %} + - + {% endif %} +
{{ row.value|escape }}
1 copyright Copyright \(c\) 2000 ACME, Inc\.