Skip to content

Commit 6cfda8f

Browse files
authored
chore: improve UX for CA error messages (#799)
1 parent f769184 commit 6cfda8f

File tree

7 files changed

+32
-25
lines changed

7 files changed

+32
-25
lines changed

src/caNotification.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ import { applySettingNameMappings } from './utils';
66
/**
77
* Interface representing the data structure for a Component Analysis (CA) Notification.
88
*/
9-
interface CANotificationData {
10-
errorMessage: string | null;
11-
done: boolean | null;
12-
uri: Uri | null;
13-
diagCount: number | null;
14-
vulnCount: Map<string, number> | null;
9+
export interface CANotificationData {
10+
uri: Uri;
11+
errorMessage?: string | null;
12+
done?: boolean | null;
13+
diagCount?: number | null;
14+
vulnCount?: Map<string, number> | null;
1515
}
1616

1717
/**

src/config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ class Config {
7272
* @returns The RHDA configuration settings.
7373
* @private
7474
*/
75-
private getRhdaConfig(): any {
75+
private getRhdaConfig(): vscode.WorkspaceConfiguration {
7676
return vscode.workspace.getConfiguration('redHatDependencyAnalytics');
7777
}
7878

src/dependencyAnalysis/analysis.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,16 @@ import { isDefined } from '../utils';
1212
import { IDependencyProvider } from '../dependencyAnalysis/collector';
1313
import { Uri } from 'vscode';
1414
import { notifications, outputChannelDep } from '../extension';
15+
import { Source } from '@trustification/exhort-api-spec/model/v4/Source';
16+
import { DependencyReport } from '@trustification/exhort-api-spec/model/v4/DependencyReport';
17+
import { Issue } from '@trustification/exhort-api-spec/model/v4/Issue';
1518

1619
/**
1720
* Represents a source object with an ID and dependencies array.
1821
*/
1922
interface ISource {
2023
id: string;
21-
dependencies: any[];
24+
dependencies: DependencyReport[];
2225
}
2326

2427
/**
@@ -83,7 +86,7 @@ class AnalysisResponse implements IAnalysisResponse {
8386
const issuesCount: number = isDefined(d, 'issues') ? d.issues.length : 0;
8487

8588
const dd = issuesCount
86-
? new DependencyData(source.id, issuesCount, '', this.getRemediation(d.issues[0]), this.getHighestSeverity(d))
89+
? new DependencyData(source.id, issuesCount, '', this.getRemediation(d.issues![0]), this.getHighestSeverity(d))
8790
: new DependencyData(source.id, issuesCount, this.getRecommendation(d), '', this.getHighestSeverity(d));
8891

8992
const resolvedRef = this.provider.resolveDependencyFromReference(d.ref);
@@ -102,7 +105,7 @@ class AnalysisResponse implements IAnalysisResponse {
102105
* @returns An array of dependencies or empty array if none exists.
103106
* @private
104107
*/
105-
private getDependencies(sourceData: any): any[] {
108+
private getDependencies(sourceData: Source): DependencyReport[] {
106109
return isDefined(sourceData, 'dependencies') ? sourceData.dependencies : [];
107110
}
108111

@@ -112,7 +115,7 @@ class AnalysisResponse implements IAnalysisResponse {
112115
* @returns The highest severity level or NONE if none exists.
113116
* @private
114117
*/
115-
private getHighestSeverity(dependency: any): string {
118+
private getHighestSeverity(dependency: DependencyReport): string {
116119
return isDefined(dependency, 'highestVulnerability', 'severity') ? dependency.highestVulnerability.severity : 'NONE';
117120
}
118121

@@ -122,7 +125,7 @@ class AnalysisResponse implements IAnalysisResponse {
122125
* @returns The remediation reference or empty string if none exists.
123126
* @private
124127
*/
125-
private getRemediation(issue: any): string {
128+
private getRemediation(issue: Issue): string {
126129
return isDefined(issue, 'remediation', 'trustedContent', 'ref') ? this.provider.resolveDependencyFromReference(issue.remediation.trustedContent.ref.split('?')[0]) : '';
127130
}
128131

@@ -132,7 +135,7 @@ class AnalysisResponse implements IAnalysisResponse {
132135
* @returns The recommendation reference or empty string if none exists.
133136
* @private
134137
*/
135-
private getRecommendation(dependency: any): string {
138+
private getRecommendation(dependency: DependencyReport): string {
136139
return isDefined(dependency, 'recommendation') ? this.provider.resolveDependencyFromReference(dependency.recommendation.split('?')[0]) : '';
137140
}
138141
}

src/dependencyReportPanel.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,6 @@ export class DependencyReportPanel {
113113
DependencyReportPanel.data = null;
114114
while (this._disposables.length) {
115115
const x = this._disposables.pop();
116-
/* istanbul ignore else */
117116
if (x) {
118117
x.dispose();
119118
}

src/exhortServices.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,18 @@ import * as vscode from 'vscode';
44
import exhort, { ImageRef, Options, parseImageRef } from '@trustification/exhort-javascript-api';
55

66
import { IImageRef, IOptions } from './imageAnalysis';
7+
import { AnalysisReport } from '@trustification/exhort-api-spec/model/v4/AnalysisReport';
78

89
/**
910
* Executes RHDA image analysis using the provided images and options.
1011
* @param images - The images to analyze.
1112
* @param options - The options for running image analysis.
12-
* @returns A Promise resolving to the analysis response in HTML format.
13+
* @returns A Promise resolving to the analysis response in HTML or object format.
1314
*/
14-
async function imageAnalysisService(images: IImageRef[], html: boolean, options: IOptions): Promise<any> {
15+
async function imageAnalysisService(images: IImageRef[], html: false, options: IOptions): Promise<{ [key: string]: AnalysisReport }>;
16+
async function imageAnalysisService(images: IImageRef[], html: true, options: IOptions): Promise<string>;
17+
18+
async function imageAnalysisService(images: IImageRef[], html: boolean, options: IOptions): Promise<string | { [key: string]: AnalysisReport }> {
1519
return await exhort.imageAnalysis(images.map(img => {
1620
if (img.platform) {
1721
return `${img.image}^^${img.platform}`;

src/extension.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { generateRHDAReport } from './rhda';
99
import { globalConfig } from './config';
1010
import { StatusMessages, PromptText } from './constants';
1111
import { caStatusBarProvider } from './caStatusBarProvider';
12-
import { CANotification } from './caNotification';
12+
import { CANotification, CANotificationData } from './caNotification';
1313
import { DepOutputChannel } from './depOutputChannel';
1414
import { record, startUp, TelemetryActions } from './redhatTelemetry';
1515
import { applySettingNameMappings, buildErrorMessage } from './utils';
@@ -27,6 +27,7 @@ export const notifications = new EventEmitter();
2727
*/
2828
export async function activate(context: vscode.ExtensionContext) {
2929
outputChannelDep = new DepOutputChannel();
30+
outputChannelDep.info(`starting RHDA extension ${context.extension.packageJSON['version']}`);
3031

3132
globalConfig.linkToSecretStorage(context);
3233

@@ -40,10 +41,11 @@ export async function activate(context: vscode.ExtensionContext) {
4041

4142
const fileHandler = new AnalysisMatcher();
4243
context.subscriptions.push(vscode.workspace.onDidSaveTextDocument((doc) => fileHandler.handle(doc)));
44+
// Anecdotaly, some extension(s) may cause did-open events for files that aren't actually open in the editor,
45+
// so this will trigger CA for files not actually open.
4346
context.subscriptions.push(vscode.workspace.onDidOpenTextDocument((doc) => fileHandler.handle(doc)));
4447
context.subscriptions.push(vscode.workspace.onDidCloseTextDocument(doc => clearCodeActionsMap(doc.uri)));
45-
// iterate all open docs, as theres no "did open doc" event for these
46-
// TODO: why is pom.xml not being picked up as background file
48+
// Iterate all open docs, as there is (in general) no did-open event for these.
4749
for (const doc of vscode.workspace.textDocuments) {
4850
fileHandler.handle(doc);
4951
}
@@ -111,7 +113,7 @@ export async function activate(context: vscode.ExtensionContext) {
111113
}
112114
};
113115

114-
notifications.on('caNotification', respData => {
116+
notifications.on('caNotification', (respData: CANotificationData) => {
115117
const notification = new CANotification(respData);
116118
caStatusBarProvider.showSummary(notification.statusText(), notification.origin());
117119
if (notification.hasWarning()) {
@@ -120,12 +122,12 @@ export async function activate(context: vscode.ExtensionContext) {
120122
}
121123
});
122124

123-
notifications.on('caError', errorData => {
125+
notifications.on('caError', (errorData: CANotificationData) => {
124126
const notification = new CANotification(errorData);
125127
caStatusBarProvider.setError();
126128

127129
// Since CA is an automated feature, only warning message will be shown on failure
128-
vscode.window.showWarningMessage(notification.errorMsg());
130+
vscode.window.showWarningMessage(`RHDA error while analyzing ${errorData.uri.fsPath}: ${notification.errorMsg()}`);
129131

130132
// Record telemetry event
131133
record(context, TelemetryActions.componentAnalysisFailed, { manifest: path.basename(notification.origin().fsPath), fileName: path.basename(notification.origin().fsPath), error: notification.errorMsg() });

src/imageAnalysis/analysis.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ class AnalysisResponse implements IAnalysisResponse {
112112
* @returns The total number of issues.
113113
* @private
114114
*/
115-
private getTotalIssues(summary: any): number {
115+
private getTotalIssues(summary: SourceSummary): number {
116116
return isDefined(summary, 'total') ? summary.total : 0;
117117
}
118118

@@ -122,7 +122,7 @@ class AnalysisResponse implements IAnalysisResponse {
122122
* @returns The highest severity level.
123123
* @private
124124
*/
125-
private getHighestSeverity(summary: any): string {
125+
private getHighestSeverity(summary: SourceSummary): string {
126126
let highestSeverity = 'NONE';
127127

128128
if (isDefined(summary, 'critical') && summary.critical > 0) {
@@ -160,7 +160,6 @@ class AnalysisResponse implements IAnalysisResponse {
160160
* @returns A Promise resolving to an AnalysisResponse object.
161161
*/
162162
async function executeImageAnalysis(diagnosticFilePath: Uri, images: IImage[]): Promise<AnalysisResponse> {
163-
164163
// Define configuration options for the component analysis request
165164
const options: IOptions = {
166165
'RHDA_TOKEN': globalConfig.telemetryId ?? '',

0 commit comments

Comments
 (0)