diff --git a/src/snyk/common/analytics/AnalyticsSender.ts b/src/snyk/common/analytics/AnalyticsSender.ts index 8ec2c74e7..32fdcc0a7 100644 --- a/src/snyk/common/analytics/AnalyticsSender.ts +++ b/src/snyk/common/analytics/AnalyticsSender.ts @@ -4,7 +4,9 @@ import { ILog } from '../logger/interfaces'; import { IConfiguration } from '../configuration/configuration'; import { sleep } from '@amplitude/experiment-node-server/dist/src/util/time'; import { IVSCodeCommands } from '../vscode/commands'; -import { SNYK_REPORT_ANALTYICS } from '../constants/commands'; +import { SNYK_REPORT_ANALYTICS } from '../constants/commands'; +import { IContextService } from '../services/contextService'; +import { SNYK_CONTEXT } from '../constants/views'; interface EventPair { event: AbstractAnalyticsEvent; @@ -17,15 +19,13 @@ export interface AbstractAnalyticsEvent {} export class AnalyticsSender { private static instance: AnalyticsSender; private eventQueue: EventPair[] = []; - private configuration: IConfiguration; - private logger: ILog; - private commandExecutor: IVSCodeCommands; - - private constructor(logger: ILog, configuration: IConfiguration, commandExecutor: IVSCodeCommands) { - this.logger = logger; - this.configuration = configuration; - this.commandExecutor = commandExecutor; + constructor( + private logger: ILog, + private configuration: IConfiguration, + private commandExecutor: IVSCodeCommands, + private contextService: IContextService, + ) { void this.start(); } @@ -33,9 +33,10 @@ export class AnalyticsSender { logger: ILog, configuration: IConfiguration, commandExecutor: IVSCodeCommands, + contextService: IContextService, ): AnalyticsSender { if (!AnalyticsSender.instance) { - AnalyticsSender.instance = new AnalyticsSender(logger, configuration, commandExecutor); + AnalyticsSender.instance = new AnalyticsSender(logger, configuration, commandExecutor, contextService); } return AnalyticsSender.instance; } @@ -45,10 +46,14 @@ export class AnalyticsSender { while (true) { // eslint-disable-next-line no-await-in-loop const authToken = await this.configuration.getToken(); + const initialized: boolean = (this.contextService.viewContext[SNYK_CONTEXT.INITIALIZED] as boolean) ?? false; + const hasEvents = this.eventQueue.length > 0; + const authenticated = authToken && authToken.trim() !== ''; + const iAmTired = !(initialized && authenticated && hasEvents); - if (this.eventQueue.length === 0 || !authToken || authToken.trim() === '') { + if (iAmTired) { // eslint-disable-next-line no-await-in-loop - await sleep(1000); + await sleep(5000); continue; } @@ -56,10 +61,8 @@ export class AnalyticsSender { for (let i = 0; i < copyForSending.length; i++) { const eventPair = copyForSending[i]; try { - const args = []; - args.push(eventPair.event); // eslint-disable-next-line no-await-in-loop - await this.commandExecutor.executeCommand(SNYK_REPORT_ANALTYICS, args); + await this.commandExecutor.executeCommand(SNYK_REPORT_ANALYTICS, JSON.stringify(eventPair.event)); eventPair.callback(); } catch (error) { // eslint-disable-next-line @typescript-eslint/no-base-to-string diff --git a/src/snyk/common/configuration/configuration.ts b/src/snyk/common/configuration/configuration.ts index 91ab2ddce..066ebbb2f 100644 --- a/src/snyk/common/configuration/configuration.ts +++ b/src/snyk/common/configuration/configuration.ts @@ -30,7 +30,6 @@ import { } from '../constants/settings'; import SecretStorageAdapter from '../vscode/secretStorage'; import { IVSCodeWorkspace } from '../vscode/workspace'; -import { MEMENTO_LS_CHECKSUM } from '../constants/globalState'; const NEWISSUES = 'Net new issues'; diff --git a/src/snyk/common/constants/commands.ts b/src/snyk/common/constants/commands.ts index 37c6ffbf0..b49959089 100644 --- a/src/snyk/common/constants/commands.ts +++ b/src/snyk/common/constants/commands.ts @@ -30,7 +30,7 @@ export const SNYK_FEATURE_FLAG_COMMAND = 'snyk.getFeatureFlagStatus'; export const SNYK_CLEAR_CACHE_COMMAND = 'snyk.clearCache'; export const SNYK_CLEAR_PERSISTED_CACHE_COMMAND = 'snyk.clearPersistedCache'; export const SNYK_GENERATE_ISSUE_DESCRIPTION = 'snyk.generateIssueDescription'; -export const SNYK_REPORT_ANALTYICS = 'snyk.reportAnalytics'; +export const SNYK_REPORT_ANALYTICS = 'snyk.reportAnalytics'; // custom Snyk constants used in commands export const SNYK_CONTEXT_PREFIX = 'snyk:'; diff --git a/src/snyk/common/views/issueTreeProvider.ts b/src/snyk/common/views/issueTreeProvider.ts index f1084c960..0eb42114b 100644 --- a/src/snyk/common/views/issueTreeProvider.ts +++ b/src/snyk/common/views/issueTreeProvider.ts @@ -1,10 +1,10 @@ import _, { flatten } from 'lodash'; import * as vscode from 'vscode'; // todo: invert dependency import { IConfiguration, IssueViewOptions } from '../../common/configuration/configuration'; -import { Issue, IssueSeverity, ScanProduct, LsErrorMessage } from '../../common/languageServer/types'; +import { Issue, IssueSeverity, LsErrorMessage } from '../../common/languageServer/types'; import { messages as commonMessages } from '../../common/messages/analysisMessages'; import { IContextService } from '../../common/services/contextService'; -import { IProductService, ProductService } from '../../common/services/productService'; +import { IProductService } from '../../common/services/productService'; import { AnalysisTreeNodeProvider } from '../../common/views/analysisTreeNodeProvider'; import { INodeIcon, InternalType, NODE_ICONS, TreeNode } from '../../common/views/treeNode'; import { IVSCodeLanguages } from '../../common/vscode/languages'; diff --git a/src/snyk/extension.ts b/src/snyk/extension.ts index bb2f167ee..d4fedb230 100644 --- a/src/snyk/extension.ts +++ b/src/snyk/extension.ts @@ -39,7 +39,6 @@ import { } from './common/constants/views'; import { ErrorHandler } from './common/error/errorHandler'; import { ExperimentService } from './common/experiment/services/experimentService'; -import { LanguageServer } from './common/languageServer/languageServer'; import { StaticLsApi } from './common/languageServer/staticLsApi'; import { Logger } from './common/logger/logger'; import { DownloadService } from './common/services/downloadService'; @@ -81,8 +80,9 @@ import { ClearCacheService } from './common/services/CacheService'; import { InMemory, Persisted } from './common/constants/general'; import { GitAPI, GitExtension, Repository } from './common/git'; import { AnalyticsSender } from './common/analytics/AnalyticsSender'; -import { AnalyticsEvent } from './common/analytics/AnalyticsEvent'; import { MEMENTO_ANALYTICS_PLUGIN_INSTALLED_SENT } from './common/constants/globalState'; +import { AnalyticsEvent } from './common/analytics/AnalyticsEvent'; +import { LanguageServer } from './common/languageServer/languageServer'; class SnykExtension extends SnykLib implements IExtension { public async activate(vscodeContext: vscode.ExtensionContext): Promise { @@ -422,17 +422,23 @@ class SnykExtension extends SnykLib implements IExtension { // The codeEnabled context depends on an LS command await this.languageServer.start(); + // initialize contexts + await this.contextService.setContext(SNYK_CONTEXT.INITIALIZED, true); + + // Fetch feature flag to determine whether to use the new LSP-based rendering. // feature flags depend on the language server this.featureFlagService = new FeatureFlagService(vsCodeCommands); await this.setupFeatureFlags(); - // Fetch feature flag to determine whether to use the new LSP-based rendering. + this.sendPluginInstalledEvent(); - // initialize contexts - await this.contextService.setContext(SNYK_CONTEXT.INITIALIZED, true); + // Actually start analysis + this.runScan(); + } + private sendPluginInstalledEvent() { // start analytics sender and send plugin installed event - const analyticsSender = AnalyticsSender.getInstance(Logger, configuration, this.commandController); + const analyticsSender = AnalyticsSender.getInstance(Logger, configuration, vsCodeCommands, this.contextService); const pluginInstalledSent = extensionContext.getGlobalStateValue(MEMENTO_ANALYTICS_PLUGIN_INSTALLED_SENT) ?? false; @@ -445,9 +451,6 @@ class SnykExtension extends SnykLib implements IExtension { void extensionContext.updateGlobalStateValue(MEMENTO_ANALYTICS_PLUGIN_INSTALLED_SENT, true); }); } - - // Actually start analysis - this.runScan(); } public async deactivate(): Promise { diff --git a/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewProvider.ts b/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewProvider.ts index 1d4bb55e2..206a9d477 100644 --- a/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewProvider.ts +++ b/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewProvider.ts @@ -93,8 +93,6 @@ export class CodeSuggestionWebviewProvider } async showPanel(issue: Issue): Promise { - const isIgnoresEnabled = configuration.getFeatureFlag(FEATURE_FLAGS.consistentIgnores); - try { await this.focusSecondEditorGroup(); if (this.panel) { @@ -120,7 +118,7 @@ export class CodeSuggestionWebviewProvider 'snyk-code.svg', ); // TODO: delete this when SNYK_GENERATE_ISSUE_DESCRIPTION command is in stable CLI. - let html: string = ''; + let html: string; if (issue.additionalData.details) { html = issue.additionalData.details; } else {