Skip to content

Commit

Permalink
refactor: remove Snyk Code logic from shared issueTreeProvider
Browse files Browse the repository at this point in the history
  • Loading branch information
carlos-snyk committed Mar 27, 2024
1 parent 04066e0 commit c061471
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 55 deletions.
12 changes: 0 additions & 12 deletions src/snyk/common/views/analysisTreeNodeProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,6 @@ export abstract class AnalysisTreeNodeProvider extends TreeNodeProvider {
return 0;
};

protected getDurationTreeNode(): TreeNode {
const ts = new Date(this.statusProvider.lastAnalysisTimestamp);
const time = ts.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
const day = ts.toLocaleDateString([], { year: '2-digit', month: '2-digit', day: '2-digit' });

return new TreeNode({
text: messages.duration(time, day),
});
}

protected getNoSeverityFiltersSelectedTreeNode(): TreeNode | null {
const anyFilterEnabled = Object.values<boolean>(this.configuration.severityFilter).find(enabled => !!enabled);
if (anyFilterEnabled) {
Expand Down Expand Up @@ -81,6 +71,4 @@ export abstract class AnalysisTreeNodeProvider extends TreeNodeProvider {
},
});
}

protected abstract getFilteredIssues(issues: readonly unknown[]): readonly unknown[];
}
68 changes: 29 additions & 39 deletions src/snyk/common/views/issueTreeProvider.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import _ from 'lodash';
import _, { flatten } from 'lodash';
import * as vscode from 'vscode'; // todo: invert dependency
import { IConfiguration } from '../../common/configuration/configuration';
import { CodeIssueData, Issue, IssueSeverity } from '../../common/languageServer/types';
Expand All @@ -13,9 +13,6 @@ import { Command, Range } from '../../common/vscode/types';
interface ISeverityCounts {
[severity: string]: number;
}
interface IssueAdditionalData {
hasAIFix?: boolean;
}

export abstract class ProductIssueTreeProvider<T> extends AnalysisTreeNodeProvider {
constructor(
Expand Down Expand Up @@ -86,8 +83,7 @@ export abstract class ProductIssueTreeProvider<T> extends AnalysisTreeNodeProvid
];
}

const [resultNodes, nIssues, AIFixVulnCount] = this.getResultNodes();
nodes.push(...resultNodes);
nodes.push(...this.getResultNodes());

const folderResults = Array.from(this.productService.result.values());
const allFailed = folderResults.every(folderResult => folderResult instanceof Error);
Expand All @@ -99,29 +95,40 @@ export abstract class ProductIssueTreeProvider<T> extends AnalysisTreeNodeProvid

const topNodes: (TreeNode | null)[] = [
new TreeNode({
text: this.getIssueFoundText(nIssues),
text: this.getIssueFoundText(this.getTotalIssueCount()),
}),
this.getFixableIssuesNode(this.getFixableCount()),
this.getNoSeverityFiltersSelectedTreeNode(),
];

if ('codeService' in this) {
topNodes.push(
new TreeNode({
text: (this as any).getAIFixableIssuesText(AIFixVulnCount),
}),
);
}

// this.getDurationTreeNode(),
topNodes.push(this.getNoSeverityFiltersSelectedTreeNode());

nodes.unshift(...topNodes.filter((n): n is TreeNode => n !== null));
return nodes;
}

getResultNodes(): [TreeNode[], number, number | null] {
getFixableIssuesNode(_fixableIssueCount: number): TreeNode | null {
return null; // optionally overridden by products
}

getFilteredIssues(): Issue<T>[] {
const folderResults = Array.from(this.productService.result.values());
const successfulResults = flatten(folderResults.filter((result): result is Issue<T>[] => Array.isArray(result)));
return this.filterIssues(successfulResults);
}

getTotalIssueCount(): number {
return this.getFilteredIssues().length;
}

getFixableCount(): number {
return this.getFilteredIssues().filter(issue => this.isFixableIssue(issue)).length;
}

isFixableIssue(_issue: Issue<T>) {
return false; // optionally overridden by products
}

getResultNodes(): TreeNode[] {
const nodes: TreeNode[] = [];
let totalVulnCount = 0;
let AIFixVulnCoun = 0;

for (const result of this.productService.result.entries()) {
const folderPath = result[0];
Expand Down Expand Up @@ -155,13 +162,8 @@ export abstract class ProductIssueTreeProvider<T> extends AnalysisTreeNodeProvid

const issueNodes = filteredIssues.map(issue => {
fileSeverityCounts[issue.severity] += 1;
totalVulnCount++;
folderVulnCount++;

if (this.getAIFix(issue)) {
AIFixVulnCoun++;
}

const issueRange = this.getIssueRange(issue);
const params: {
text: string;
Expand Down Expand Up @@ -235,29 +237,17 @@ export abstract class ProductIssueTreeProvider<T> extends AnalysisTreeNodeProvid
}
}

return [nodes, totalVulnCount, AIFixVulnCoun];
return nodes;
}

protected getIssueFoundText(nIssues: number): string {
return `Snyk found ${!nIssues ? 'no issues! ✅' : `${nIssues} issue${nIssues === 1 ? '' : 's'}`}`;
}

protected getAIFixableIssuesText(issuesCount: number | null): string {
return issuesCount && issuesCount > 0
? `⚡️ ${issuesCount} ${issuesCount === 1 ? 'vulnerability' : 'vulnerabilities'} can be fixed by Snyk DeepCode AI`
: 'There are no vulnerabilities fixable by Snyk DeepCode AI';
}

protected getIssueDescriptionText(dir: string | undefined, issueCount: number): string | undefined {
return `${dir} - ${issueCount} issue${issueCount === 1 ? '' : 's'}`;
}

// todo: Obsolete. Remove after OSS scans migration to LS
protected getFilteredIssues(diagnostics: readonly unknown[]): readonly unknown[] {
// Diagnostics are already filtered by the analyzer
return diagnostics;
}

static getHighestSeverity(counts: ISeverityCounts): IssueSeverity {
for (const s of [IssueSeverity.Critical, IssueSeverity.High, IssueSeverity.Medium, IssueSeverity.Low]) {
if (counts[s]) return s;
Expand Down
17 changes: 17 additions & 0 deletions src/snyk/snykCode/views/issueTreeProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { IVSCodeLanguages } from '../../common/vscode/languages';
import { messages } from '../messages/analysis';
import { IssueUtils } from '../utils/issueUtils';
import { CodeIssueCommandArg } from './interfaces';
import { TreeNode } from '../../common/views/treeNode';

export class IssueTreeProvider extends ProductIssueTreeProvider<CodeIssueData> {
constructor(
Expand Down Expand Up @@ -67,4 +68,20 @@ export class IssueTreeProvider extends ProductIssueTreeProvider<CodeIssueData> {
],
};
}

isFixableIssue(issue: Issue<CodeIssueData>): boolean {
return issue.additionalData.hasAIFix;
}

getFixableIssuesNode(fixableIssueCount: number): TreeNode {
return new TreeNode({
text: this.getAIFixableIssuesText(fixableIssueCount),
});
}

private getAIFixableIssuesText(issuesCount: number): string {
return issuesCount > 0
? `⚡️ ${issuesCount} ${issuesCount === 1 ? 'vulnerability' : 'vulnerabilities'} can be fixed by Snyk DeepCode AI`
: 'There are no vulnerabilities fixable by Snyk DeepCode AI';
}
}
6 changes: 2 additions & 4 deletions src/snyk/snykOss/providers/ossVulnerabilityTreeProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,8 @@ export default class OssIssueTreeProvider extends ProductIssueTreeProvider<OssIs
return super.getRootChildren();
}

override getResultNodes(): [TreeNode[], number, null] {
override getResultNodes(): TreeNode[] {
const nodes: TreeNode[] = [];
let totalVulnCount = 0;

for (const result of this.productService.result.entries()) {
const folderPath = result[0];
Expand Down Expand Up @@ -78,7 +77,6 @@ export default class OssIssueTreeProvider extends ProductIssueTreeProvider<OssIs

const vulnerabilityNodes: TreeNode[] = filteredIssues.map((issue: Issue<OssIssueData>) => {
fileSeverityCounts[issue.severity] += 1;
totalVulnCount++;
folderVulnCount++;

return new TreeNode({
Expand Down Expand Up @@ -140,7 +138,7 @@ export default class OssIssueTreeProvider extends ProductIssueTreeProvider<OssIs
}
}

return [nodes, totalVulnCount, null];
return nodes;
}

onDidChangeTreeData = this.viewManagerService.refreshOssViewEmitter.event;
Expand Down

0 comments on commit c061471

Please sign in to comment.