scanoss 1.37.1__tar.gz → 1.39.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {scanoss-1.37.1/src/scanoss.egg-info → scanoss-1.39.0}/PKG-INFO +1 -1
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/__init__.py +1 -1
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/cli.py +174 -12
- scanoss-1.39.0/src/scanoss/data/build_date.txt +1 -0
- scanoss-1.39.0/src/scanoss/gitlabqualityreport.py +185 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/inspection/dependency_track/project_violation.py +3 -2
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/inspection/policy_check.py +0 -42
- scanoss-1.39.0/src/scanoss/inspection/raw/__init__.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/inspection/raw/component_summary.py +53 -2
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/inspection/raw/copyleft.py +3 -2
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/inspection/raw/license_summary.py +49 -1
- scanoss-1.39.0/src/scanoss/inspection/raw/match_summary.py +290 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/inspection/raw/raw_base.py +5 -10
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/inspection/raw/undeclared_component.py +3 -2
- scanoss-1.39.0/src/scanoss/inspection/utils/file_utils.py +44 -0
- scanoss-1.39.0/src/scanoss/inspection/utils/markdown_utils.py +63 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/scanners/folder_hasher.py +1 -0
- scanoss-1.39.0/src/scanoss/utils/scanoss_scan_results_utils.py +41 -0
- {scanoss-1.37.1 → scanoss-1.39.0/src/scanoss.egg-info}/PKG-INFO +1 -1
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss.egg-info/SOURCES.txt +6 -0
- scanoss-1.37.1/src/scanoss/data/build_date.txt +0 -1
- {scanoss-1.37.1 → scanoss-1.39.0}/LICENSE +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/PACKAGE.md +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/README.md +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/pyproject.toml +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/setup.cfg +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/protoc_gen_swagger/__init__.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/protoc_gen_swagger/options/__init__.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/protoc_gen_swagger/options/annotations_pb2.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/protoc_gen_swagger/options/annotations_pb2.pyi +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/protoc_gen_swagger/options/annotations_pb2_grpc.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/protoc_gen_swagger/options/openapiv2_pb2.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/protoc_gen_swagger/options/openapiv2_pb2.pyi +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/protoc_gen_swagger/options/openapiv2_pb2_grpc.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/api/__init__.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/api/common/__init__.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/api/common/v2/__init__.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/api/common/v2/scanoss_common_pb2.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/api/common/v2/scanoss_common_pb2_grpc.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/api/components/__init__.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/api/components/v2/__init__.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/api/components/v2/scanoss_components_pb2.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/api/components/v2/scanoss_components_pb2_grpc.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/api/cryptography/v2/scanoss_cryptography_pb2.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/api/cryptography/v2/scanoss_cryptography_pb2_grpc.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/api/dependencies/__init__.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/api/dependencies/v2/__init__.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/api/dependencies/v2/scanoss_dependencies_pb2.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/api/dependencies/v2/scanoss_dependencies_pb2_grpc.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/api/geoprovenance/__init__.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/api/geoprovenance/v2/__init__.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/api/geoprovenance/v2/scanoss_geoprovenance_pb2.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/api/geoprovenance/v2/scanoss_geoprovenance_pb2_grpc.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/api/licenses/__init__.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/api/licenses/v2/__init__.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/api/licenses/v2/scanoss_licenses_pb2.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/api/licenses/v2/scanoss_licenses_pb2_grpc.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/api/scanning/__init__.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/api/scanning/v2/__init__.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/api/scanning/v2/scanoss_scanning_pb2.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/api/scanning/v2/scanoss_scanning_pb2_grpc.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/api/semgrep/__init__.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/api/semgrep/v2/__init__.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/api/semgrep/v2/scanoss_semgrep_pb2.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/api/semgrep/v2/scanoss_semgrep_pb2_grpc.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/api/vulnerabilities/__init__.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/api/vulnerabilities/v2/__init__.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/api/vulnerabilities/v2/scanoss_vulnerabilities_pb2.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/api/vulnerabilities/v2/scanoss_vulnerabilities_pb2_grpc.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/components.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/constants.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/cryptography.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/csvoutput.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/cyclonedx.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/data/scanoss-settings-schema.json +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/data/spdx-exceptions.json +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/data/spdx-licenses.json +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/delta.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/export/__init__.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/export/dependency_track.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/file_filters.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/filecount.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/inspection/__init__.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/inspection/utils/license_utils.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/results.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/scancodedeps.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/scanner.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/scanners/__init__.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/scanners/container_scanner.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/scanners/scanner_config.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/scanners/scanner_hfh.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/scanoss_settings.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/scanossapi.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/scanossbase.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/scanossgrpc.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/scanpostprocessor.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/scantype.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/services/dependency_track_service.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/spdxlite.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/threadeddependencies.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/threadedscanning.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/utils/__init__.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/utils/abstract_presenter.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/utils/crc64.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/utils/file.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/utils/simhash.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/winnowing.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss.egg-info/dependency_links.txt +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss.egg-info/entry_points.txt +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss.egg-info/requires.txt +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss.egg-info/top_level.txt +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/tests/test_csv_output.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/tests/test_file_filters.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/tests/test_policy_inspect.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/tests/test_scan_post_processor.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/tests/test_spdxlite.py +0 -0
- {scanoss-1.37.1 → scanoss-1.39.0}/tests/test_winnowing.py +0 -0
|
@@ -40,6 +40,7 @@ from scanoss.inspection.dependency_track.project_violation import (
|
|
|
40
40
|
)
|
|
41
41
|
from scanoss.inspection.raw.component_summary import ComponentSummary
|
|
42
42
|
from scanoss.inspection.raw.license_summary import LicenseSummary
|
|
43
|
+
from scanoss.inspection.raw.match_summary import MatchSummary
|
|
43
44
|
from scanoss.scanners.container_scanner import (
|
|
44
45
|
DEFAULT_SYFT_COMMAND,
|
|
45
46
|
DEFAULT_SYFT_TIMEOUT,
|
|
@@ -73,6 +74,7 @@ from .constants import (
|
|
|
73
74
|
from .csvoutput import CsvOutput
|
|
74
75
|
from .cyclonedx import CycloneDx
|
|
75
76
|
from .filecount import FileCount
|
|
77
|
+
from .gitlabqualityreport import GitLabQualityReport
|
|
76
78
|
from .inspection.raw.copyleft import Copyleft
|
|
77
79
|
from .inspection.raw.undeclared_component import UndeclaredComponent
|
|
78
80
|
from .results import Results
|
|
@@ -283,7 +285,7 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
|
|
|
283
285
|
'--format',
|
|
284
286
|
'-f',
|
|
285
287
|
type=str,
|
|
286
|
-
choices=['cyclonedx', 'spdxlite', 'csv'],
|
|
288
|
+
choices=['cyclonedx', 'spdxlite', 'csv', 'glc-codequality'],
|
|
287
289
|
default='spdxlite',
|
|
288
290
|
help='Output format (optional - default: spdxlite)',
|
|
289
291
|
)
|
|
@@ -794,6 +796,66 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
|
|
|
794
796
|
help='Timeout (in seconds) for API communication (optional - default 300 sec)',
|
|
795
797
|
)
|
|
796
798
|
|
|
799
|
+
|
|
800
|
+
# ==============================================================================
|
|
801
|
+
# GitLab Integration Parser
|
|
802
|
+
# ==============================================================================
|
|
803
|
+
# Main parser for GitLab-specific inspection commands and report generation
|
|
804
|
+
p_gitlab_sub = p_inspect_sub.add_parser(
|
|
805
|
+
'gitlab',
|
|
806
|
+
aliases=['glc'],
|
|
807
|
+
description='Generate GitLab-compatible reports from SCANOSS scan results (Markdown summaries)',
|
|
808
|
+
help='Generate GitLab integration reports',
|
|
809
|
+
)
|
|
810
|
+
|
|
811
|
+
# GitLab sub-commands parser
|
|
812
|
+
# Provides access to different GitLab report formats and inspection tools
|
|
813
|
+
p_gitlab_sub_parser = p_gitlab_sub.add_subparsers(
|
|
814
|
+
title='GitLab Report Types',
|
|
815
|
+
dest='subparser_subcmd',
|
|
816
|
+
description='Available GitLab report formats for scan result analysis',
|
|
817
|
+
help='Select the type of GitLab report to generate',
|
|
818
|
+
)
|
|
819
|
+
|
|
820
|
+
# ==============================================================================
|
|
821
|
+
# GitLab Matches Summary Command
|
|
822
|
+
# ==============================================================================
|
|
823
|
+
# Analyzes scan results and generates a GitLab-compatible Markdown summary
|
|
824
|
+
p_gl_inspect_matches = p_gitlab_sub_parser.add_parser(
|
|
825
|
+
'matches',
|
|
826
|
+
aliases=['ms'],
|
|
827
|
+
description='Generate a Markdown summary report of scan matches for GitLab integration',
|
|
828
|
+
help='Generate Markdown summary report of scan matches',
|
|
829
|
+
)
|
|
830
|
+
|
|
831
|
+
# Input file argument - SCANOSS scan results in JSON format
|
|
832
|
+
p_gl_inspect_matches.add_argument(
|
|
833
|
+
'-i',
|
|
834
|
+
'--input',
|
|
835
|
+
required=True,
|
|
836
|
+
type=str,
|
|
837
|
+
help='Path to SCANOSS scan results file (JSON format) to analyze'
|
|
838
|
+
)
|
|
839
|
+
|
|
840
|
+
# Line range prefix for GitLab file navigation
|
|
841
|
+
# Enables clickable file references in the generated report that link to specific lines in GitLab
|
|
842
|
+
p_gl_inspect_matches.add_argument(
|
|
843
|
+
'-lpr',
|
|
844
|
+
'--line-range-prefix',
|
|
845
|
+
required=True,
|
|
846
|
+
type=str,
|
|
847
|
+
help='Base URL prefix for GitLab file links with line ranges (e.g., https://gitlab.com/org/project/-/blob/main)'
|
|
848
|
+
)
|
|
849
|
+
|
|
850
|
+
# Output file argument - where to save the generated Markdown report
|
|
851
|
+
p_gl_inspect_matches.add_argument(
|
|
852
|
+
'--output',
|
|
853
|
+
'-o',
|
|
854
|
+
required=False,
|
|
855
|
+
type=str,
|
|
856
|
+
help='Output file path for the generated Markdown report (default: stdout)'
|
|
857
|
+
)
|
|
858
|
+
|
|
797
859
|
# TODO Move to the command call def location
|
|
798
860
|
# RAW results
|
|
799
861
|
p_inspect_raw_undeclared.set_defaults(func=inspect_undeclared)
|
|
@@ -807,6 +869,8 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
|
|
|
807
869
|
p_inspect_legacy_component_summary.set_defaults(func=inspect_component_summary)
|
|
808
870
|
# Dependency Track
|
|
809
871
|
p_inspect_dt_project_violation.set_defaults(func=inspect_dep_track_project_violations)
|
|
872
|
+
# GitLab
|
|
873
|
+
p_gl_inspect_matches.set_defaults(func=inspect_gitlab_matches)
|
|
810
874
|
|
|
811
875
|
# =========================================================================
|
|
812
876
|
# END INSPECT SUBCOMMAND CONFIGURATION
|
|
@@ -929,10 +993,7 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
|
|
|
929
993
|
)
|
|
930
994
|
|
|
931
995
|
delta_sub = p_delta.add_subparsers(
|
|
932
|
-
title='Delta Commands',
|
|
933
|
-
dest='subparsercmd',
|
|
934
|
-
description='Delta sub-commands',
|
|
935
|
-
help='Delta sub-commands'
|
|
996
|
+
title='Delta Commands', dest='subparsercmd', description='Delta sub-commands', help='Delta sub-commands'
|
|
936
997
|
)
|
|
937
998
|
|
|
938
999
|
# Delta Sub-command: copy
|
|
@@ -1156,6 +1217,7 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
|
|
|
1156
1217
|
p_inspect_legacy_license_summary,
|
|
1157
1218
|
p_inspect_legacy_component_summary,
|
|
1158
1219
|
p_inspect_dt_project_violation,
|
|
1220
|
+
p_gl_inspect_matches,
|
|
1159
1221
|
c_provenance,
|
|
1160
1222
|
p_folder_scan,
|
|
1161
1223
|
p_folder_hash,
|
|
@@ -1165,9 +1227,15 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
|
|
|
1165
1227
|
p_crypto_versions_in_range,
|
|
1166
1228
|
c_licenses,
|
|
1167
1229
|
e_dt,
|
|
1168
|
-
p_copy
|
|
1230
|
+
p_copy,
|
|
1169
1231
|
]:
|
|
1170
|
-
p.add_argument(
|
|
1232
|
+
p.add_argument(
|
|
1233
|
+
'--debug',
|
|
1234
|
+
'-d',
|
|
1235
|
+
action='store_true',
|
|
1236
|
+
default=os.environ.get('SCANOSS_DEBUG', '').lower() == 'true',
|
|
1237
|
+
help='Enable debug messages (can also be set via environment variable SCANOSS_DEBUG)',
|
|
1238
|
+
)
|
|
1171
1239
|
p.add_argument('--trace', '-t', action='store_true', help='Enable trace messages, including API posts')
|
|
1172
1240
|
p.add_argument('--quiet', '-q', action='store_true', help='Enable quiet mode')
|
|
1173
1241
|
|
|
@@ -1186,12 +1254,29 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
|
|
|
1186
1254
|
sys.exit(1)
|
|
1187
1255
|
elif (
|
|
1188
1256
|
args.subparser
|
|
1189
|
-
in (
|
|
1190
|
-
'
|
|
1257
|
+
in (
|
|
1258
|
+
'utils',
|
|
1259
|
+
'ut',
|
|
1260
|
+
'component',
|
|
1261
|
+
'comp',
|
|
1262
|
+
'inspect',
|
|
1263
|
+
'insp',
|
|
1264
|
+
'ins',
|
|
1265
|
+
'crypto',
|
|
1266
|
+
'cr',
|
|
1267
|
+
'export',
|
|
1268
|
+
'exp',
|
|
1269
|
+
'delta',
|
|
1270
|
+
'dl',
|
|
1271
|
+
)
|
|
1191
1272
|
) and not args.subparsercmd:
|
|
1192
1273
|
parser.parse_args([args.subparser, '--help']) # Force utils helps to be displayed
|
|
1193
1274
|
sys.exit(1)
|
|
1194
|
-
elif (
|
|
1275
|
+
elif (
|
|
1276
|
+
(args.subparser in 'inspect')
|
|
1277
|
+
and (args.subparsercmd in ('raw', 'dt', 'glc', 'gitlab'))
|
|
1278
|
+
and (args.subparser_subcmd is None)
|
|
1279
|
+
):
|
|
1195
1280
|
parser.parse_args([args.subparser, args.subparsercmd, '--help']) # Force utils helps to be displayed
|
|
1196
1281
|
sys.exit(1)
|
|
1197
1282
|
args.func(parser, args) # Execute the function associated with the sub-command
|
|
@@ -1612,6 +1697,11 @@ def convert(parser, args):
|
|
|
1612
1697
|
print_stderr('Producing CSV report...')
|
|
1613
1698
|
csvo = CsvOutput(debug=args.debug, output_file=args.output)
|
|
1614
1699
|
success = csvo.produce_from_file(args.input)
|
|
1700
|
+
elif args.format == 'glc-codequality':
|
|
1701
|
+
if not args.quiet:
|
|
1702
|
+
print_stderr('Producing GitLab code quality report...')
|
|
1703
|
+
glc_code_quality = GitLabQualityReport(debug=args.debug, trace=args.trace, quiet=args.quiet)
|
|
1704
|
+
success = glc_code_quality.produce_from_file(args.input, output_file=args.output)
|
|
1615
1705
|
else:
|
|
1616
1706
|
print_stderr(f'ERROR: Unknown output format (--format): {args.format}')
|
|
1617
1707
|
if not success:
|
|
@@ -1885,6 +1975,69 @@ def inspect_dep_track_project_violations(parser, args):
|
|
|
1885
1975
|
sys.exit(1)
|
|
1886
1976
|
|
|
1887
1977
|
|
|
1978
|
+
def inspect_gitlab_matches(parser,args):
|
|
1979
|
+
"""
|
|
1980
|
+
Handle GitLab matches the summary inspection command.
|
|
1981
|
+
|
|
1982
|
+
Analyzes SCANOSS scan results and generates a GitLab-compatible Markdown summary
|
|
1983
|
+
report of component matches. The report includes match details, file locations,
|
|
1984
|
+
and optionally clickable links to source files in GitLab repositories.
|
|
1985
|
+
|
|
1986
|
+
This command processes SCANOSS scan output and creates human-readable Markdown.
|
|
1987
|
+
|
|
1988
|
+
Parameters
|
|
1989
|
+
----------
|
|
1990
|
+
parser : ArgumentParser
|
|
1991
|
+
Command line parser object for help display
|
|
1992
|
+
args : Namespace
|
|
1993
|
+
Parsed command line arguments containing:
|
|
1994
|
+
- input: Path to SCANOSS scan results file (JSON format) to analyze
|
|
1995
|
+
- line_range_prefix: Base URL prefix for generating GitLab file links with line ranges
|
|
1996
|
+
(e.g., 'https://gitlab.com/org/project/-/blob/main')
|
|
1997
|
+
- output: Optional output file path for the generated Markdown report (default: stdout)
|
|
1998
|
+
- debug: Enable debug output for troubleshooting
|
|
1999
|
+
- trace: Enable trace-level logging
|
|
2000
|
+
- quiet: Suppress informational messages
|
|
2001
|
+
|
|
2002
|
+
Notes
|
|
2003
|
+
-----
|
|
2004
|
+
- The output is formatted in Markdown for optimal display in GitLab
|
|
2005
|
+
- Line range prefix enables clickable file references in the report
|
|
2006
|
+
- If output is not specified, the report is written to stdout
|
|
2007
|
+
"""
|
|
2008
|
+
|
|
2009
|
+
if args.input is None:
|
|
2010
|
+
parser.parse_args([args.subparser, '-h'])
|
|
2011
|
+
sys.exit(1)
|
|
2012
|
+
|
|
2013
|
+
if args.line_range_prefix is None:
|
|
2014
|
+
parser.parse_args([args.subparser, '-h'])
|
|
2015
|
+
sys.exit(1)
|
|
2016
|
+
|
|
2017
|
+
# Initialize output file if specified (create/truncate)
|
|
2018
|
+
if args.output:
|
|
2019
|
+
initialise_empty_file(args.output)
|
|
2020
|
+
|
|
2021
|
+
try:
|
|
2022
|
+
# Create GitLab matches summary generator with configuration
|
|
2023
|
+
match_summary = MatchSummary(
|
|
2024
|
+
debug=args.debug,
|
|
2025
|
+
trace=args.trace,
|
|
2026
|
+
quiet=args.quiet,
|
|
2027
|
+
scanoss_results_path=args.input, # Path to SCANOSS JSON results
|
|
2028
|
+
output=args.output, # Output file path or None for stdout
|
|
2029
|
+
line_range_prefix=args.line_range_prefix, # GitLab URL prefix for file links
|
|
2030
|
+
)
|
|
2031
|
+
|
|
2032
|
+
# Execute the summary generation
|
|
2033
|
+
match_summary.run()
|
|
2034
|
+
except Exception as e:
|
|
2035
|
+
# Handle any errors during report generation
|
|
2036
|
+
print_stderr(e)
|
|
2037
|
+
if args.debug:
|
|
2038
|
+
traceback.print_exc()
|
|
2039
|
+
sys.exit(1)
|
|
2040
|
+
|
|
1888
2041
|
# =============================================================================
|
|
1889
2042
|
# END INSPECT COMMAND HANDLERS
|
|
1890
2043
|
# =============================================================================
|
|
@@ -2634,6 +2787,7 @@ def initialise_empty_file(filename: str):
|
|
|
2634
2787
|
print_stderr(f'Error: Unable to create output file {filename}: {e}')
|
|
2635
2788
|
sys.exit(1)
|
|
2636
2789
|
|
|
2790
|
+
|
|
2637
2791
|
def delta_copy(parser, args):
|
|
2638
2792
|
"""
|
|
2639
2793
|
Handle delta copy command.
|
|
@@ -2661,8 +2815,15 @@ def delta_copy(parser, args):
|
|
|
2661
2815
|
initialise_empty_file(args.output)
|
|
2662
2816
|
try:
|
|
2663
2817
|
# Create and configure delta copy command
|
|
2664
|
-
delta = Delta(
|
|
2665
|
-
|
|
2818
|
+
delta = Delta(
|
|
2819
|
+
debug=args.debug,
|
|
2820
|
+
trace=args.trace,
|
|
2821
|
+
quiet=args.quiet,
|
|
2822
|
+
filepath=args.input,
|
|
2823
|
+
folder=args.folder,
|
|
2824
|
+
output=args.output,
|
|
2825
|
+
root_dir=args.root,
|
|
2826
|
+
)
|
|
2666
2827
|
# Execute copy and exit with appropriate status code
|
|
2667
2828
|
status, _ = delta.copy()
|
|
2668
2829
|
sys.exit(status)
|
|
@@ -2672,6 +2833,7 @@ def delta_copy(parser, args):
|
|
|
2672
2833
|
traceback.print_exc()
|
|
2673
2834
|
sys.exit(1)
|
|
2674
2835
|
|
|
2836
|
+
|
|
2675
2837
|
def main():
|
|
2676
2838
|
"""
|
|
2677
2839
|
Run the ScanOSS CLI
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
date: 20251027150435, utime: 1761577475
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"""
|
|
2
|
+
SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
Copyright (c) 2025, SCANOSS
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in
|
|
14
|
+
all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
22
|
+
THE SOFTWARE.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
import json
|
|
26
|
+
import os
|
|
27
|
+
import sys
|
|
28
|
+
from dataclasses import dataclass
|
|
29
|
+
|
|
30
|
+
from .scanossbase import ScanossBase
|
|
31
|
+
from .utils import scanoss_scan_results_utils
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclass
|
|
35
|
+
class Lines:
|
|
36
|
+
begin: int
|
|
37
|
+
|
|
38
|
+
@dataclass
|
|
39
|
+
class Location:
|
|
40
|
+
path: str
|
|
41
|
+
lines: Lines
|
|
42
|
+
|
|
43
|
+
@dataclass
|
|
44
|
+
class CodeQuality:
|
|
45
|
+
description: str
|
|
46
|
+
check_name: str
|
|
47
|
+
fingerprint: str
|
|
48
|
+
severity: str
|
|
49
|
+
location: Location
|
|
50
|
+
|
|
51
|
+
def to_dict(self):
|
|
52
|
+
"""Convert to dictionary for JSON serialization."""
|
|
53
|
+
return {
|
|
54
|
+
"description": self.description,
|
|
55
|
+
"check_name": self.check_name,
|
|
56
|
+
"fingerprint": self.fingerprint,
|
|
57
|
+
"severity": self.severity,
|
|
58
|
+
"location": {
|
|
59
|
+
"path": self.location.path,
|
|
60
|
+
"lines": {
|
|
61
|
+
"begin": self.location.lines.begin
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
class GitLabQualityReport(ScanossBase):
|
|
67
|
+
"""
|
|
68
|
+
GitLabCodeQuality management class
|
|
69
|
+
Handle all interaction with GitLab Code Quality Report formatting
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
def __init__(self, debug: bool = False, trace: bool = False, quiet: bool = False):
|
|
73
|
+
"""
|
|
74
|
+
Initialise the GitLabCodeQuality class
|
|
75
|
+
"""
|
|
76
|
+
super().__init__(debug, trace, quiet)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _get_code_quality(self, file_name: str, result: dict) -> CodeQuality or None:
|
|
80
|
+
if not result.get('file_hash'):
|
|
81
|
+
self.print_debug(f"Warning: no hash found for result: {result}")
|
|
82
|
+
return None
|
|
83
|
+
|
|
84
|
+
if result.get('id') == 'file':
|
|
85
|
+
description = f"File match found in: {file_name}"
|
|
86
|
+
return CodeQuality(
|
|
87
|
+
description=description,
|
|
88
|
+
check_name=file_name,
|
|
89
|
+
fingerprint=result.get('file_hash'),
|
|
90
|
+
severity="info",
|
|
91
|
+
location=Location(
|
|
92
|
+
path=file_name,
|
|
93
|
+
lines = Lines(
|
|
94
|
+
begin= 1
|
|
95
|
+
)
|
|
96
|
+
)
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
if not result.get('lines'):
|
|
100
|
+
self.print_debug(f"Warning: No lines found for result: {result}")
|
|
101
|
+
return None
|
|
102
|
+
lines = scanoss_scan_results_utils.get_lines(result.get('lines'))
|
|
103
|
+
if len(lines) == 0:
|
|
104
|
+
self.print_debug(f"Warning: empty lines for result: {result}")
|
|
105
|
+
return None
|
|
106
|
+
end_line = lines[len(lines) - 1] if len(lines) > 1 else lines[0]
|
|
107
|
+
description = f"Snippet found in: {file_name} - lines {lines[0]}-{end_line}"
|
|
108
|
+
return CodeQuality(
|
|
109
|
+
description=description,
|
|
110
|
+
check_name=file_name,
|
|
111
|
+
fingerprint=result.get('file_hash'),
|
|
112
|
+
severity="info",
|
|
113
|
+
location=Location(
|
|
114
|
+
path=file_name,
|
|
115
|
+
lines=Lines(
|
|
116
|
+
begin=lines[0]
|
|
117
|
+
)
|
|
118
|
+
)
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
def _write_output(self, data: list[CodeQuality], output_file: str = None) -> bool:
|
|
122
|
+
"""Write the Gitlab Code Quality Report to output."""
|
|
123
|
+
try:
|
|
124
|
+
json_data = [item.to_dict() for item in data]
|
|
125
|
+
file = open(output_file, 'w') if output_file else sys.stdout
|
|
126
|
+
print(json.dumps(json_data, indent=2), file=file)
|
|
127
|
+
if output_file:
|
|
128
|
+
file.close()
|
|
129
|
+
return True
|
|
130
|
+
except Exception as e:
|
|
131
|
+
self.print_stderr(f'Error writing output: {str(e)}')
|
|
132
|
+
return False
|
|
133
|
+
|
|
134
|
+
def _produce_from_json(self, data: dict, output_file: str = None) -> bool:
|
|
135
|
+
code_quality = []
|
|
136
|
+
for file_name, results in data.items():
|
|
137
|
+
for result in results:
|
|
138
|
+
if not result.get('id'):
|
|
139
|
+
self.print_debug(f"Warning: No ID found for result: {result}")
|
|
140
|
+
continue
|
|
141
|
+
if result.get('id') != 'snippet' and result.get('id') != 'file':
|
|
142
|
+
self.print_debug(f"Skipping non-snippet/file match: {result}")
|
|
143
|
+
continue
|
|
144
|
+
code_quality_item = self._get_code_quality(file_name, result)
|
|
145
|
+
if code_quality_item:
|
|
146
|
+
code_quality.append(code_quality_item)
|
|
147
|
+
else:
|
|
148
|
+
self.print_debug(f"Warning: No Code Quality found for result: {result}")
|
|
149
|
+
self._write_output(data=code_quality,output_file=output_file)
|
|
150
|
+
return True
|
|
151
|
+
|
|
152
|
+
def _produce_from_str(self, json_str: str, output_file: str = None) -> bool:
|
|
153
|
+
"""
|
|
154
|
+
Produce Gitlab Code Quality Report output from input JSON string
|
|
155
|
+
:param json_str: input JSON string
|
|
156
|
+
:param output_file: Output file (optional)
|
|
157
|
+
:return: True if successful, False otherwise
|
|
158
|
+
"""
|
|
159
|
+
if not json_str:
|
|
160
|
+
self.print_stderr('ERROR: No JSON string provided to parse.')
|
|
161
|
+
return False
|
|
162
|
+
try:
|
|
163
|
+
data = json.loads(json_str)
|
|
164
|
+
except Exception as e:
|
|
165
|
+
self.print_stderr(f'ERROR: Problem parsing input JSON: {e}')
|
|
166
|
+
return False
|
|
167
|
+
return self._produce_from_json(data, output_file)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def produce_from_file(self, json_file: str, output_file: str = None) -> bool:
|
|
171
|
+
"""
|
|
172
|
+
Parse plain/raw input JSON file and produce GitLab Code Quality JSON output
|
|
173
|
+
:param json_file:
|
|
174
|
+
:param output_file:
|
|
175
|
+
:return: True if successful, False otherwise
|
|
176
|
+
"""
|
|
177
|
+
if not json_file:
|
|
178
|
+
self.print_stderr('ERROR: No JSON file provided to parse.')
|
|
179
|
+
return False
|
|
180
|
+
if not os.path.isfile(json_file):
|
|
181
|
+
self.print_stderr(f'ERROR: JSON file does not exist or is not a file: {json_file}')
|
|
182
|
+
return False
|
|
183
|
+
with open(json_file, 'r') as f:
|
|
184
|
+
success = self._produce_from_str(f.read(), output_file)
|
|
185
|
+
return success
|
{scanoss-1.37.1 → scanoss-1.39.0}/src/scanoss/inspection/dependency_track/project_violation.py
RENAMED
|
@@ -28,6 +28,7 @@ from typing import Any, Dict, List, Optional, TypedDict
|
|
|
28
28
|
|
|
29
29
|
from ...services.dependency_track_service import DependencyTrackService
|
|
30
30
|
from ..policy_check import PolicyCheck, PolicyStatus
|
|
31
|
+
from ..utils.markdown_utils import generate_jira_table, generate_table
|
|
31
32
|
|
|
32
33
|
# Constants
|
|
33
34
|
PROCESSING_RETRY_DELAY = 5 # seconds
|
|
@@ -195,7 +196,7 @@ class DependencyTrackProjectViolationPolicyCheck(PolicyCheck[PolicyViolationDict
|
|
|
195
196
|
Returns:
|
|
196
197
|
Dictionary with formatted Markdown details and summary
|
|
197
198
|
"""
|
|
198
|
-
return self._md_summary_generator(project_violations,
|
|
199
|
+
return self._md_summary_generator(project_violations, generate_table)
|
|
199
200
|
|
|
200
201
|
def _jira_markdown(self, data: list[PolicyViolationDict]) -> Dict[str, Any]:
|
|
201
202
|
"""
|
|
@@ -207,7 +208,7 @@ class DependencyTrackProjectViolationPolicyCheck(PolicyCheck[PolicyViolationDict
|
|
|
207
208
|
Returns:
|
|
208
209
|
Dictionary containing Jira markdown formatted results and summary
|
|
209
210
|
"""
|
|
210
|
-
return self._md_summary_generator(data,
|
|
211
|
+
return self._md_summary_generator(data, generate_jira_table)
|
|
211
212
|
|
|
212
213
|
def is_project_updated(self, dt_project: Dict[str, Any]) -> bool:
|
|
213
214
|
"""
|
|
@@ -137,48 +137,6 @@ class PolicyCheck(ScanossBase, Generic[T]):
|
|
|
137
137
|
"""
|
|
138
138
|
pass
|
|
139
139
|
|
|
140
|
-
def generate_table(self, headers, rows, centered_columns=None):
|
|
141
|
-
"""
|
|
142
|
-
Generate a Markdown table.
|
|
143
|
-
|
|
144
|
-
:param headers: List of headers for the table.
|
|
145
|
-
:param rows: List of rows for the table.
|
|
146
|
-
:param centered_columns: List of column indices to be centered.
|
|
147
|
-
:return: A string representing the Markdown table.
|
|
148
|
-
"""
|
|
149
|
-
col_sep = ' | '
|
|
150
|
-
centered_column_set = set(centered_columns or [])
|
|
151
|
-
if headers is None:
|
|
152
|
-
self.print_stderr('ERROR: Header are no set')
|
|
153
|
-
return None
|
|
154
|
-
|
|
155
|
-
# Decide which separator to use
|
|
156
|
-
def create_separator(index):
|
|
157
|
-
if centered_columns is None:
|
|
158
|
-
return '-'
|
|
159
|
-
return ':-:' if index in centered_column_set else '-'
|
|
160
|
-
|
|
161
|
-
# Build the row separator
|
|
162
|
-
row_separator = col_sep + col_sep.join(create_separator(index) for index, _ in enumerate(headers)) + col_sep
|
|
163
|
-
# build table rows
|
|
164
|
-
table_rows = [col_sep + col_sep.join(headers) + col_sep, row_separator]
|
|
165
|
-
table_rows.extend(col_sep + col_sep.join(row) + col_sep for row in rows)
|
|
166
|
-
return '\n'.join(table_rows)
|
|
167
|
-
|
|
168
|
-
def generate_jira_table(self, headers, rows, centered_columns=None):
|
|
169
|
-
col_sep = '*|*'
|
|
170
|
-
if headers is None:
|
|
171
|
-
self.print_stderr('ERROR: Header are no set')
|
|
172
|
-
return None
|
|
173
|
-
|
|
174
|
-
table_header = '|*' + col_sep.join(headers) + '*|\n'
|
|
175
|
-
table = table_header
|
|
176
|
-
for row in rows:
|
|
177
|
-
if len(headers) == len(row):
|
|
178
|
-
table += '|' + '|'.join(row) + '|\n'
|
|
179
|
-
|
|
180
|
-
return table
|
|
181
|
-
|
|
182
140
|
def _get_formatter(self) -> Callable[[List[dict]], Dict[str, Any]] or None:
|
|
183
141
|
"""
|
|
184
142
|
Get the appropriate formatter function based on the specified format.
|
|
File without changes
|
|
@@ -21,13 +21,58 @@ SPDX-License-Identifier: MIT
|
|
|
21
21
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
22
22
|
THE SOFTWARE.
|
|
23
23
|
"""
|
|
24
|
-
|
|
25
24
|
import json
|
|
25
|
+
from typing import Any
|
|
26
26
|
|
|
27
|
+
from ..policy_check import T
|
|
27
28
|
from .raw_base import RawBase
|
|
28
29
|
|
|
29
30
|
|
|
30
31
|
class ComponentSummary(RawBase):
|
|
32
|
+
|
|
33
|
+
def _json(self, data: dict[str,Any]) -> dict[str,Any]:
|
|
34
|
+
"""
|
|
35
|
+
Format component summary data as JSON.
|
|
36
|
+
|
|
37
|
+
This method returns the component summary data in its original JSON structure
|
|
38
|
+
without any transformation. The data can be directly serialized to JSON format.
|
|
39
|
+
|
|
40
|
+
:param data: Dictionary containing component summary information including:
|
|
41
|
+
- components: List of component-license pairs with status and metadata
|
|
42
|
+
- totalComponents: Total number of unique components
|
|
43
|
+
- undeclaredComponents: Number of components with 'pending' status
|
|
44
|
+
- declaredComponents: Number of components with 'identified' status
|
|
45
|
+
- totalFilesDetected: Total count of files where components were detected
|
|
46
|
+
- totalFilesUndeclared: Count of files with undeclared components
|
|
47
|
+
- totalFilesDeclared: Count of files with declared components
|
|
48
|
+
:return: The same data dictionary, ready for JSON serialization
|
|
49
|
+
"""
|
|
50
|
+
return data
|
|
51
|
+
|
|
52
|
+
def _markdown(self, data: list[T]) -> dict[str, Any]:
|
|
53
|
+
"""
|
|
54
|
+
Format component summary data as Markdown (not yet implemented).
|
|
55
|
+
|
|
56
|
+
This method is intended to convert component summary data into a human-readable
|
|
57
|
+
Markdown format with tables and formatted sections.
|
|
58
|
+
|
|
59
|
+
:param data: List of component summary items to format
|
|
60
|
+
:return: Dictionary containing formatted Markdown output
|
|
61
|
+
"""
|
|
62
|
+
pass
|
|
63
|
+
|
|
64
|
+
def _jira_markdown(self, data: list[T]) -> dict[str, Any]:
|
|
65
|
+
"""
|
|
66
|
+
Format component summary data as Jira-flavored Markdown (not yet implemented).
|
|
67
|
+
|
|
68
|
+
This method is intended to convert component summary data into Jira-compatible
|
|
69
|
+
Markdown format, which may include Jira-specific syntax for tables and formatting.
|
|
70
|
+
|
|
71
|
+
:param data: List of component summary items to format
|
|
72
|
+
:return: Dictionary containing Jira-formatted Markdown output
|
|
73
|
+
"""
|
|
74
|
+
pass
|
|
75
|
+
|
|
31
76
|
def _get_component_summary_from_components(self, scan_components: list)-> dict:
|
|
32
77
|
"""
|
|
33
78
|
Get a component summary from detected components.
|
|
@@ -84,10 +129,16 @@ class ComponentSummary(RawBase):
|
|
|
84
129
|
self._get_components_data(self.results, components)
|
|
85
130
|
return self._convert_components_to_list(components)
|
|
86
131
|
|
|
132
|
+
def _format(self, component_summary) -> str:
|
|
133
|
+
# TODO: Implement formatter to support dynamic outputs
|
|
134
|
+
json_data = self._json(component_summary)
|
|
135
|
+
return json.dumps(json_data, indent=2)
|
|
136
|
+
|
|
87
137
|
def run(self):
|
|
88
138
|
components = self._get_components()
|
|
89
139
|
component_summary = self._get_component_summary_from_components(components)
|
|
90
|
-
|
|
140
|
+
output = self._format(component_summary)
|
|
141
|
+
self.print_to_file_or_stdout(output, self.output)
|
|
91
142
|
return component_summary
|
|
92
143
|
#
|
|
93
144
|
# End of ComponentSummary Class
|
|
@@ -27,6 +27,7 @@ from dataclasses import dataclass
|
|
|
27
27
|
from typing import Any, Dict, List
|
|
28
28
|
|
|
29
29
|
from ..policy_check import PolicyStatus
|
|
30
|
+
from ..utils.markdown_utils import generate_jira_table, generate_table
|
|
30
31
|
from .raw_base import RawBase
|
|
31
32
|
|
|
32
33
|
|
|
@@ -111,7 +112,7 @@ class Copyleft(RawBase[Component]):
|
|
|
111
112
|
:param components: List of components with copyleft licenses
|
|
112
113
|
:return: Dictionary with formatted Markdown details and summary
|
|
113
114
|
"""
|
|
114
|
-
return self._md_summary_generator(components,
|
|
115
|
+
return self._md_summary_generator(components, generate_table)
|
|
115
116
|
|
|
116
117
|
def _jira_markdown(self, components: list[Component]) -> Dict[str, Any]:
|
|
117
118
|
"""
|
|
@@ -120,7 +121,7 @@ class Copyleft(RawBase[Component]):
|
|
|
120
121
|
:param components: List of components with copyleft licenses
|
|
121
122
|
:return: Dictionary with formatted Markdown details and summary
|
|
122
123
|
"""
|
|
123
|
-
return self._md_summary_generator(components,
|
|
124
|
+
return self._md_summary_generator(components, generate_jira_table)
|
|
124
125
|
|
|
125
126
|
def _md_summary_generator(self, components: list[Component], table_generator):
|
|
126
127
|
"""
|