Skip to content

Commit 0c3974f

Browse files
committed
chore:SP-3607 refactor inspect module
1 parent 5d04af9 commit 0c3974f

File tree

15 files changed

+290
-274
lines changed

15 files changed

+290
-274
lines changed

Makefile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,13 @@ publish_test: ## Publish the Python package to TestPyPI
5050
@echo "Publishing package to TestPyPI..."
5151
twine upload --repository testpypi dist/*
5252

53+
linter: ## Run ruff linter with docker
54+
docker run --rm -v $(PWD):/src -w /src ghcr.io/astral-sh/ruff:0.14.2 check $$(git diff --name-only --diff-filter=ACMR | grep '\.py$$' | xargs)
55+
56+
fix-linter: ## Run ruff linter with docker
57+
docker run --rm -v $(PWD):/src -w /src ghcr.io/astral-sh/ruff:0.14.2 check $$(git diff --name-only --diff-filter=ACMR | grep '\.py$$' | xargs) --fix
58+
59+
5360
publish: ## Publish Python package to PyPI
5461
@echo "Publishing package to PyPI..."
5562
twine upload dist/*

src/scanoss/cli.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,6 @@
3535
from scanoss.cryptography import Cryptography, create_cryptography_config_from_args
3636
from scanoss.delta import Delta
3737
from scanoss.export.dependency_track import DependencyTrackExporter
38-
from scanoss.inspection.dependency_track.project_violation import (
39-
DependencyTrackProjectViolationPolicyCheck,
40-
)
41-
from scanoss.inspection.raw.component_summary import ComponentSummary
42-
from scanoss.inspection.raw.license_summary import LicenseSummary
43-
from scanoss.inspection.raw.match_summary import MatchSummary
4438
from scanoss.scanners.container_scanner import (
4539
DEFAULT_SYFT_COMMAND,
4640
DEFAULT_SYFT_TIMEOUT,
@@ -75,8 +69,14 @@
7569
from .cyclonedx import CycloneDx
7670
from .filecount import FileCount
7771
from .gitlabqualityreport import GitLabQualityReport
78-
from .inspection.raw.copyleft import Copyleft
79-
from .inspection.raw.undeclared_component import UndeclaredComponent
72+
from .inspection.policy_check.dependency_track.project_violation import (
73+
DependencyTrackProjectViolationPolicyCheck,
74+
)
75+
from .inspection.policy_check.scanoss.copyleft import Copyleft
76+
from .inspection.policy_check.scanoss.undeclared_component import UndeclaredComponent
77+
from .inspection.summary.component_summary import ComponentSummary
78+
from .inspection.summary.license_summary import LicenseSummary
79+
from .inspection.summary.match_summary import MatchSummary
8080
from .results import Results
8181
from .scancodedeps import ScancodeDeps
8282
from .scanner import FAST_WINNOWING, Scanner
@@ -1757,7 +1757,6 @@ def inspect_copyleft(parser, args):
17571757
exclude=args.exclude, # Licenses to ignore
17581758
explicit=args.explicit, # Explicit license list
17591759
)
1760-
17611760
# Execute inspection and exit with appropriate status code
17621761
status, _ = i_copyleft.run()
17631762
sys.exit(status)

src/scanoss/inspection/policy_check/dependency_track/__init__.py

Whitespace-only changes.

src/scanoss/inspection/dependency_track/project_violation.py renamed to src/scanoss/inspection/policy_check/dependency_track/project_violation.py

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@
2626
from datetime import datetime
2727
from typing import Any, Dict, List, Optional, TypedDict
2828

29-
from ...services.dependency_track_service import DependencyTrackService
30-
from ..policy_check import PolicyCheck, PolicyStatus
31-
from ..utils.markdown_utils import generate_jira_table, generate_table
29+
from ....services.dependency_track_service import DependencyTrackService
30+
from ...utils.markdown_utils import generate_jira_table, generate_table
31+
from ..policy_check import PolicyCheck, PolicyOutput, PolicyStatus
3232

3333
# Constants
3434
PROCESSING_RETRY_DELAY = 5 # seconds
@@ -171,7 +171,7 @@ def __init__( # noqa: PLR0913
171171
self.url = url.strip().rstrip('/') if url else None
172172
self.dep_track_service = DependencyTrackService(self.api_key, self.url, debug=debug, trace=trace, quiet=quiet)
173173

174-
def _json(self, project_violations: list[PolicyViolationDict]) -> Dict[str, Any]:
174+
def _json(self, project_violations: list[PolicyViolationDict]) -> PolicyOutput:
175175
"""
176176
Format project violations as JSON.
177177
@@ -181,12 +181,12 @@ def _json(self, project_violations: list[PolicyViolationDict]) -> Dict[str, Any]
181181
Returns:
182182
Dictionary containing JSON formatted results and summary
183183
"""
184-
return {
185-
"details": json.dumps(project_violations, indent=2),
186-
"summary": f'{len(project_violations)} policy violations were found.\n',
187-
}
184+
return PolicyOutput(
185+
details= json.dumps(project_violations, indent=2),
186+
summary= f'{len(project_violations)} policy violations were found.\n',
187+
)
188188

189-
def _markdown(self, project_violations: list[PolicyViolationDict]) -> Dict[str, Any]:
189+
def _markdown(self, project_violations: list[PolicyViolationDict]) -> PolicyOutput:
190190
"""
191191
Format Dependency Track violations to Markdown format.
192192
@@ -198,7 +198,7 @@ def _markdown(self, project_violations: list[PolicyViolationDict]) -> Dict[str,
198198
"""
199199
return self._md_summary_generator(project_violations, generate_table)
200200

201-
def _jira_markdown(self, data: list[PolicyViolationDict]) -> Dict[str, Any]:
201+
def _jira_markdown(self, data: list[PolicyViolationDict]) -> PolicyOutput:
202202
"""
203203
Format project violations for Jira Markdown.
204204
@@ -357,8 +357,7 @@ def _set_project_id(self) -> None:
357357
self.print_stderr(f'Error: Failed to get project uuid from: {dt_project}')
358358
raise ValueError(f'Error: Project {self.project_name}@{self.project_version} does not have a valid UUID')
359359

360-
@staticmethod
361-
def _sort_project_violations(violations: List[PolicyViolationDict]) -> List[PolicyViolationDict]:
360+
def _sort_project_violations(self,violations: List[PolicyViolationDict]) -> List[PolicyViolationDict]:
362361
"""
363362
Sort project violations by priority.
364363
@@ -377,7 +376,7 @@ def _sort_project_violations(violations: List[PolicyViolationDict]) -> List[Poli
377376
key=lambda x: -type_priority.get(x.get('type', 'OTHER'), 1)
378377
)
379378

380-
def _md_summary_generator(self, project_violations: list[PolicyViolationDict], table_generator):
379+
def _md_summary_generator(self, project_violations: list[PolicyViolationDict], table_generator) -> PolicyOutput:
381380
"""
382381
Generates a Markdown summary of project policy violations.
383382
@@ -396,10 +395,10 @@ def _md_summary_generator(self, project_violations: list[PolicyViolationDict], t
396395
"""
397396
if project_violations is None:
398397
self.print_stderr('Warning: No project violations found. Returning empty results.')
399-
return {
400-
"details": "h3. Dependency Track Project Violations\n\nNo policy violations found.\n",
401-
"summary": "0 policy violations were found.\n",
402-
}
398+
return PolicyOutput(
399+
details= "h3. Dependency Track Project Violations\n\nNo policy violations found.\n",
400+
summary= "0 policy violations were found.\n",
401+
)
403402
headers = ['State', 'Risk Type', 'Policy Name', 'Component', 'Date']
404403
c_cols = [0, 1]
405404
rows: List[List[str]] = []
@@ -424,11 +423,11 @@ def _md_summary_generator(self, project_violations: list[PolicyViolationDict], t
424423
]
425424
rows.append(row)
426425
# End for loop
427-
return {
428-
"details": f'### Dependency Track Project Violations\n{table_generator(headers, rows, c_cols)}\n\n'
426+
return PolicyOutput(
427+
details= f'### Dependency Track Project Violations\n{table_generator(headers, rows, c_cols)}\n\n'
429428
f'View project in Dependency Track [here]({self.url}/projects/{self.project_id}).\n',
430-
"summary": f'{len(project_violations)} policy violations were found.\n'
431-
}
429+
summary= f'{len(project_violations)} policy violations were found.\n'
430+
)
432431

433432
def run(self) -> int:
434433
"""
@@ -470,10 +469,11 @@ def run(self) -> int:
470469
self.print_stderr('Error: Invalid format specified.')
471470
return PolicyStatus.ERROR.value
472471
# Format and output data - handle empty results gracefully
473-
data = formatter(self._sort_project_violations(dt_project_violations))
474-
self.print_to_file_or_stdout(data['details'], self.output)
475-
self.print_to_file_or_stderr(data['summary'], self.status)
472+
policy_output = formatter(self._sort_project_violations(dt_project_violations))
473+
self.print_to_file_or_stdout(policy_output.details, self.output)
474+
self.print_to_file_or_stderr(policy_output.summary, self.status)
476475
# Return appropriate status based on violation count
477476
if len(dt_project_violations) > 0:
478477
return PolicyStatus.POLICY_FAIL.value
479478
return PolicyStatus.POLICY_SUCCESS.value
479+

src/scanoss/inspection/policy_check.py renamed to src/scanoss/inspection/policy_check/policy_check.py

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@
2222
THE SOFTWARE.
2323
"""
2424

25-
from abc import abstractmethod
25+
from abc import ABC, abstractmethod
2626
from enum import Enum
27-
from typing import Any, Callable, Dict, Generic, List, TypeVar
27+
from typing import Callable, Dict, Generic, List, NamedTuple, TypeVar
2828

29-
from ..scanossbase import ScanossBase
30-
from .utils.license_utils import LicenseUtil
29+
from ...scanossbase import ScanossBase
30+
from ..utils.license_utils import LicenseUtil
3131

3232

3333
class PolicyStatus(Enum):
@@ -46,9 +46,13 @@ class PolicyStatus(Enum):
4646
# End of PolicyStatus Class
4747
#
4848

49+
class PolicyOutput(NamedTuple):
50+
details: str
51+
summary: str
52+
4953
T = TypeVar('T')
5054

51-
class PolicyCheck(ScanossBase, Generic[T]):
55+
class PolicyCheck(ScanossBase, Generic[T], ABC):
5256
"""
5357
A base class for implementing various software policy checks.
5458
@@ -80,7 +84,7 @@ def __init__( # noqa: PLR0913
8084
self.output = output
8185

8286
@abstractmethod
83-
def run(self):
87+
def run(self)-> tuple[int,PolicyOutput]:
8488
"""
8589
Execute the policy check process.
8690
@@ -91,14 +95,14 @@ def run(self):
9195
3. Formatting the results
9296
4. Saving the output to files if required
9397
94-
:return: A tuple containing:
98+
:return: A named tuple containing two elements:
9599
- First element: PolicyStatus enum value (SUCCESS, FAIL, or ERROR)
96-
- Second element: Dictionary containing the inspection results
100+
- Second element: PolicyOutput A tuple containing the policy results.
97101
"""
98102
pass
99103

100104
@abstractmethod
101-
def _json(self, data: list[T]) -> Dict[str, Any]:
105+
def _json(self, data: list[T]) -> PolicyOutput:
102106
"""
103107
Format the policy checks results as JSON.
104108
This method should be implemented by subclasses to create a Markdown representation
@@ -112,7 +116,7 @@ def _json(self, data: list[T]) -> Dict[str, Any]:
112116
pass
113117

114118
@abstractmethod
115-
def _markdown(self, data: list[T]) -> Dict[str, Any]:
119+
def _markdown(self, data: list[T]) -> PolicyOutput:
116120
"""
117121
Generate Markdown output for the policy check results.
118122
@@ -125,7 +129,7 @@ def _markdown(self, data: list[T]) -> Dict[str, Any]:
125129
pass
126130

127131
@abstractmethod
128-
def _jira_markdown(self, data: list[T]) -> Dict[str, Any]:
132+
def _jira_markdown(self, data: list[T]) -> PolicyOutput:
129133
"""
130134
Generate Markdown output for the policy check results.
131135
@@ -137,15 +141,15 @@ def _jira_markdown(self, data: list[T]) -> Dict[str, Any]:
137141
"""
138142
pass
139143

140-
def _get_formatter(self) -> Callable[[List[dict]], Dict[str, Any]] or None:
144+
def _get_formatter(self) -> Callable[[List[dict]], PolicyOutput]:
141145
"""
142146
Get the appropriate formatter function based on the specified format.
143147
144148
:return: Formatter function (either _json or _markdown)
145149
"""
146150
valid_format = self._is_valid_format()
147151
if not valid_format:
148-
return None
152+
raise ValueError('Invalid format specified')
149153
# a map of which format function to return
150154
function_map = {
151155
'json': self._json,
@@ -205,14 +209,14 @@ def _generate_formatter_report(self, components: list[Dict]):
205209
if formatter is None:
206210
return PolicyStatus.ERROR.value, {}
207211
# Format the results
208-
data = formatter(components)
212+
policy_output = formatter(components)
209213
## Save outputs if required
210-
self.print_to_file_or_stdout(data['details'], self.output)
211-
self.print_to_file_or_stderr(data['summary'], self.status)
214+
self.print_to_file_or_stdout(policy_output.details, self.output)
215+
self.print_to_file_or_stderr(policy_output.summary, self.status)
212216
# Check to see if we have policy violations
213217
if len(components) > 0:
214-
return PolicyStatus.POLICY_FAIL.value, data
215-
return PolicyStatus.POLICY_SUCCESS.value, data
218+
return PolicyStatus.POLICY_FAIL.value, policy_output
219+
return PolicyStatus.POLICY_SUCCESS.value, policy_output
216220
#
217221
# End of PolicyCheck Class
218222
#

src/scanoss/inspection/policy_check/scanoss/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)