Skip to content

Commit

Permalink
feat: show message if no option is configured [IDE-332] (#464)
Browse files Browse the repository at this point in the history
* feat: show message if no option is configured

* test: add integration tests using vscode

* refactor: check feature flag

* chore: remove unused vars

---------

Co-authored-by: Catalina Oyaneder <[email protected]>
  • Loading branch information
teodora-sandu and cat2608 authored Jun 4, 2024
1 parent ffd88f3 commit d23e75d
Show file tree
Hide file tree
Showing 9 changed files with 295 additions and 9 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## [2.9.2]
- Injects custom styling for the HTML panel used by Snyk Code for consistent ignores.
- Add warning messages in the Tree View for the issue view options used in consistent ignores.

## [2.8.1]
- Lower the strictness of custom endpoint regex validation so that single tenant APIs are allowed.
Expand Down
2 changes: 2 additions & 0 deletions src/snyk/common/configuration/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ export type FeaturesConfiguration = {
export interface IssueViewOptions {
ignoredIssues: boolean;
openIssues: boolean;

[option: string]: boolean;
}

export interface SeverityFilter {
Expand Down
3 changes: 3 additions & 0 deletions src/snyk/common/messages/analysisMessages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ export const messages = {
clickToProblem: 'Click here to see the problem.',
scanRunning: 'Scanning...',
allSeverityFiltersDisabled: 'Please enable severity filters to see the results.',
allIssueViewOptionsDisabled: 'Adjust your Issue View Options to see all issues.',
openIssueViewOptionDisabled: 'Adjust your Issue View Options to see open issues.',
ignoredIssueViewOptionDisabled: 'Adjust your Issue View Options to see ignored issues.',
duration: (time: string, day: string): string => `Analysis finished at ${time}, ${day}`,
noWorkspaceTrustDescription:
'None of workspace folders were trusted. If you trust the workspace, you can add it to the list of trusted folders in the extension settings, or when prompted by the extension next time.',
Expand Down
50 changes: 49 additions & 1 deletion src/snyk/common/views/analysisTreeNodeProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@ import _ from 'lodash';
import * as path from 'path';
import { AnalysisStatusProvider } from '../analysis/statusProvider';
import { IConfiguration } from '../configuration/configuration';
import { SNYK_SHOW_LS_OUTPUT_COMMAND } from '../constants/commands';
import { SNYK_SHOW_LS_OUTPUT_COMMAND, VSCODE_GO_TO_SETTINGS_COMMAND } from '../constants/commands';
import { messages } from '../messages/analysisMessages';
import { NODE_ICONS, TreeNode } from './treeNode';
import { TreeNodeProvider } from './treeNodeProvider';
import { SNYK_NAME_EXTENSION, SNYK_PUBLISHER } from '../constants/general';
import { configuration } from '../configuration/instance';
import { FEATURE_FLAGS } from '../constants/featureFlags';

export abstract class AnalysisTreeNodeProvider extends TreeNodeProvider {
constructor(protected readonly configuration: IConfiguration, private statusProvider: AnalysisStatusProvider) {
Expand Down Expand Up @@ -47,6 +50,51 @@ export abstract class AnalysisTreeNodeProvider extends TreeNodeProvider {
});
}

protected getNoIssueViewOptionsSelectedTreeNode(numIssues: number, ignoredIssueCount: number): TreeNode | null {
const isIgnoresEnabled = configuration.getFeatureFlag(FEATURE_FLAGS.consistentIgnores);
if (!isIgnoresEnabled) {
return null;
}

const anyOptionEnabled = Object.values<boolean>(this.configuration.issueViewOptions).find(enabled => !!enabled);
if (!anyOptionEnabled) {
return new TreeNode({
text: messages.allIssueViewOptionsDisabled,
});
}

if (numIssues === 0) {
return null;
}

// if only ignored issues are enabled, then let the customer know to adjust their settings
if (numIssues === ignoredIssueCount && !this.configuration.issueViewOptions.ignoredIssues) {
return new TreeNode({
text: messages.ignoredIssueViewOptionDisabled,
command: {
command: VSCODE_GO_TO_SETTINGS_COMMAND,
title: '',
arguments: [`@ext:${SNYK_PUBLISHER}.${SNYK_NAME_EXTENSION}`],
},
});
}

// if only open issues are enabled, then let the customer know to adjust their settings
if (ignoredIssueCount === 0 && !this.configuration.issueViewOptions.openIssues) {
return new TreeNode({
text: messages.openIssueViewOptionDisabled,
command: {
command: VSCODE_GO_TO_SETTINGS_COMMAND,
title: '',
arguments: [`@ext:${SNYK_PUBLISHER}.${SNYK_NAME_EXTENSION}`],
},
});
}

// if all options are enabled we don't want to show a warning
return null;
}

protected getErrorEncounteredTreeNode(scanPath?: string): TreeNode {
return new TreeNode({
icon: NODE_ICONS.error,
Expand Down
27 changes: 23 additions & 4 deletions src/snyk/common/views/issueTreeProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,25 @@ export abstract class ProductIssueTreeProvider<T> extends AnalysisTreeNodeProvid

nodes.sort(this.compareNodes);

const totalIssueCount = this.getTotalIssueCount();
const ignoredIssueCount = this.getIgnoredCount();

const topNodes: (TreeNode | null)[] = [
new TreeNode({
text: this.getIssueFoundText(this.getTotalIssueCount()),
text: this.getIssueFoundText(totalIssueCount, ignoredIssueCount),
}),
this.getFixableIssuesNode(this.getFixableCount()),
this.getNoSeverityFiltersSelectedTreeNode(),
];
const noSeverityFiltersSelectedWarning = this.getNoSeverityFiltersSelectedTreeNode();
if (noSeverityFiltersSelectedWarning !== null) {
topNodes.push(noSeverityFiltersSelectedWarning);
} else {
const noIssueViewOptionSelectedWarning = this.getNoIssueViewOptionsSelectedTreeNode(
totalIssueCount,
ignoredIssueCount,
);
topNodes.push(noIssueViewOptionSelectedWarning);
}

nodes.unshift(...topNodes.filter((n): n is TreeNode => n !== null));
return nodes;
Expand All @@ -103,7 +115,9 @@ export abstract class ProductIssueTreeProvider<T> extends AnalysisTreeNodeProvid

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

Expand All @@ -115,6 +129,11 @@ export abstract class ProductIssueTreeProvider<T> extends AnalysisTreeNodeProvid
return this.getFilteredIssues().filter(issue => this.isFixableIssue(issue)).length;
}

getIgnoredCount(): number {
const ignoredIssues = this.getFilteredIssues().filter(issue => issue.isIgnored);
return ignoredIssues.length;
}

isFixableIssue(_issue: Issue<T>) {
return false; // optionally overridden by products
}
Expand Down Expand Up @@ -255,7 +274,7 @@ export abstract class ProductIssueTreeProvider<T> extends AnalysisTreeNodeProvid
return nodes;
}

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

Expand Down
15 changes: 13 additions & 2 deletions src/snyk/snykCode/views/securityIssueTreeProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { IViewManagerService } from '../../common/services/viewManagerService';
import { TreeNode } from '../../common/views/treeNode';
import { IVSCodeLanguages } from '../../common/vscode/languages';
import { IssueTreeProvider } from './issueTreeProvider';
import { FEATURE_FLAGS } from '../../common/constants/featureFlags';

export default class CodeSecurityIssueTreeProvider extends IssueTreeProvider {
constructor(
Expand Down Expand Up @@ -38,9 +39,19 @@ export default class CodeSecurityIssueTreeProvider extends IssueTreeProvider {
return `${dir} - ${issueCount} ${issueCount === 1 ? 'vulnerability' : 'vulnerabilities'}`;
}

protected getIssueFoundText(nIssues: number): string {
protected getIssueFoundText(nIssues: number, ignoredIssueCount: number): string {
if (nIssues > 0) {
return nIssues === 1 ? `${nIssues} vulnerability found by Snyk` : `✋ ${nIssues} vulnerabilities found by Snyk`;
let text;
if (nIssues === 1) {
text = `${nIssues} vulnerability found by Snyk`;
} else {
text = `✋ ${nIssues} vulnerabilities found by Snyk`;
}
const isIgnoresEnabled = configuration.getFeatureFlag(FEATURE_FLAGS.consistentIgnores);
if (isIgnoresEnabled) {
text += `, ${ignoredIssueCount} ignored`;
}
return text;
} else {
return '✅ Congrats! No vulnerabilities found!';
}
Expand Down
2 changes: 1 addition & 1 deletion src/snyk/snykIac/views/iacIssueTreeProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export default class IacIssueTreeProvider extends ProductIssueTreeProvider<IacIs
return `${dir} - ${issueCount} ${issueCount === 1 ? 'issue' : 'issues'}`;
}

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

Expand Down
2 changes: 1 addition & 1 deletion src/snyk/snykOss/providers/ossVulnerabilityTreeProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ export default class OssIssueTreeProvider extends ProductIssueTreeProvider<OssIs
return `${dir} - ${issueCount} ${issueCount === 1 ? 'vulnerability' : 'vulnerabilities'}`;
}

getIssueFoundText(nIssues: number): string {
getIssueFoundText(nIssues: number, _: number): string {
return `Snyk found ${
!nIssues ? 'no vulnerabilities! ✅' : `${nIssues} ${nIssues === 1 ? 'vulnerability' : 'vulnerabilities'}`
}`;
Expand Down
Loading

0 comments on commit d23e75d

Please sign in to comment.