|
1 | | -from typing import TYPE_CHECKING, List |
| 1 | +from collections import defaultdict |
| 2 | +from typing import TYPE_CHECKING, List, Tuple |
2 | 3 |
|
3 | 4 | from cycode.cli.cli_types import SeverityOption |
4 | 5 | from cycode.cli.consts import SECRET_SCAN_TYPE |
|
22 | 23 | LINE_NUMBER_COLUMN = column_builder.build(name='Line Number') |
23 | 24 | COLUMN_NUMBER_COLUMN = column_builder.build(name='Column Number') |
24 | 25 | VIOLATION_LENGTH_COLUMN = column_builder.build(name='Violation Length') |
25 | | -VIOLATION_COLUMN = column_builder.build(name='Violation') |
| 26 | +VIOLATION_COLUMN = column_builder.build(name='Violation', highlight=False) |
26 | 27 |
|
27 | 28 |
|
28 | 29 | class TablePrinter(TablePrinterBase): |
29 | 30 | def _print_results(self, local_scan_results: List['LocalScanResult']) -> None: |
30 | 31 | table = self._get_table() |
31 | 32 |
|
| 33 | + detections_with_documents = [] |
32 | 34 | for local_scan_result in local_scan_results: |
33 | 35 | for document_detections in local_scan_result.document_detections: |
34 | | - for detection in document_detections.detections: |
35 | | - self._enrich_table_with_values(table, detection, document_detections.document) |
| 36 | + detections_with_documents.extend( |
| 37 | + [(detection, document_detections.document) for detection in document_detections.detections] |
| 38 | + ) |
| 39 | + |
| 40 | + for detection, document in self._sort_and_group_detections(detections_with_documents): |
| 41 | + self._enrich_table_with_values(table, detection, document) |
36 | 42 |
|
37 | 43 | self._print_table(table) |
38 | 44 | self._print_report_urls(local_scan_results, self.ctx.obj.get('aggregation_report_url')) |
39 | 45 |
|
| 46 | + @staticmethod |
| 47 | + def __severity_sort_key(detection_with_document: Tuple[Detection, Document]) -> int: |
| 48 | + detection, _ = detection_with_document |
| 49 | + severity = detection.severity if detection.severity else '' |
| 50 | + return SeverityOption.get_member_weight(severity) |
| 51 | + |
| 52 | + def _sort_detections_by_severity( |
| 53 | + self, detections_with_documents: List[Tuple[Detection, Document]] |
| 54 | + ) -> List[Tuple[Detection, Document]]: |
| 55 | + return sorted(detections_with_documents, key=self.__severity_sort_key, reverse=True) |
| 56 | + |
| 57 | + @staticmethod |
| 58 | + def __file_path_sort_key(detection_with_document: Tuple[Detection, Document]) -> str: |
| 59 | + _, document = detection_with_document |
| 60 | + return document.path |
| 61 | + |
| 62 | + def _sort_detections_by_file_path( |
| 63 | + self, detections_with_documents: List[Tuple[Detection, Document]] |
| 64 | + ) -> List[Tuple[Detection, Document]]: |
| 65 | + return sorted(detections_with_documents, key=self.__file_path_sort_key) |
| 66 | + |
| 67 | + def _sort_and_group_detections( |
| 68 | + self, detections_with_documents: List[Tuple[Detection, Document]] |
| 69 | + ) -> List[Tuple[Detection, Document]]: |
| 70 | + """Sort detections by severity and group by file name.""" |
| 71 | + result = [] |
| 72 | + |
| 73 | + # we sort detections by file path to make persist output order |
| 74 | + sorted_detections = self._sort_detections_by_file_path(detections_with_documents) |
| 75 | + |
| 76 | + grouped_by_file_path = defaultdict(list) |
| 77 | + for detection, document in sorted_detections: |
| 78 | + grouped_by_file_path[document.path].append((detection, document)) |
| 79 | + |
| 80 | + for file_path_group in grouped_by_file_path.values(): |
| 81 | + result.extend(self._sort_detections_by_severity(file_path_group)) |
| 82 | + |
| 83 | + return result |
| 84 | + |
40 | 85 | def _get_table(self) -> Table: |
41 | 86 | table = Table() |
42 | 87 |
|
|
0 commit comments