Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: fetch feature flag for Code Consistent Ignores [IDE-274] #455

Merged
merged 12 commits into from
May 13, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions src/snyk/common/configuration/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import _ from 'lodash';
import path from 'path';
import { URL } from 'url';
import { IDE_NAME_SHORT, SNYK_TOKEN_KEY } from '../constants/general';
import { SNYK_FEATURE_FLAG_COMMAND } from '../constants/commands';
import {
ADVANCED_ADDITIONAL_PARAMETERS_SETTING,
ADVANCED_ADVANCED_MODE_SETTING,
Expand All @@ -26,6 +27,8 @@ import {
} from '../constants/settings';
import SecretStorageAdapter from '../vscode/secretStorage';
import { IVSCodeWorkspace } from '../vscode/workspace';
import { vsCodeCommands } from '../vscode/commands';
import type { FeatureFlagStatus } from '../types';

export type FeaturesConfiguration = {
ossEnabled: boolean | undefined;
Expand Down Expand Up @@ -54,6 +57,12 @@ export interface IConfiguration {

authHost: string;

fetchAndSetFeatureFlag(flagName: string): Promise<void>;

getFeatureFlag(flagName: string): boolean;

setFeatureFlag(flagName: string, value: boolean): void;

getToken(): Promise<string | undefined>;

setToken(token: string | undefined): Promise<void>;
Expand Down Expand Up @@ -115,6 +124,8 @@ export class Configuration implements IConfiguration {
private readonly defaultAuthHost = 'https://snyk.io';
private readonly defaultOssApiEndpoint = `${this.defaultAuthHost}/api/v1`;

private featureFlag: { [key: string]: boolean } = {};

constructor(private processEnv: NodeJS.ProcessEnv = process.env, private workspace: IVSCodeWorkspace) {}

getInsecure(): boolean {
Expand All @@ -134,6 +145,23 @@ export class Configuration implements IConfiguration {
return preview;
}

public async fetchAndSetFeatureFlag(flagName: string): Promise<void> {
try {
const ffStatus = await vsCodeCommands.executeCommand<FeatureFlagStatus>(SNYK_FEATURE_FLAG_COMMAND, flagName);
this.setFeatureFlag(flagName, ffStatus?.ok ?? false);
} catch (error) {
console.warn(`Failed to fetch feature flag ${flagName}: ${error}`);
}
}

getFeatureFlag(flagName: string): boolean {
return this.featureFlag[flagName] ?? false;
}

setFeatureFlag(flagName: string, value: boolean): void {
this.featureFlag[flagName] = value;
}

private static async getPackageJsonConfig(): Promise<{ version: string; preview: boolean }> {
return (await import(path.join('../../../..', 'package.json'))) as { version: string; preview: boolean };
}
Expand Down
1 change: 1 addition & 0 deletions src/snyk/common/constants/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export const SNYK_WORKSPACE_SCAN_COMMAND = 'snyk.workspace.scan';
export const SNYK_TRUST_WORKSPACE_FOLDERS_COMMAND = 'snyk.trustWorkspaceFolders';
export const SNYK_GET_ACTIVE_USER = 'snyk.getActiveUser';
export const SNYK_CODE_FIX_DIFFS_COMMAND = 'snyk.code.fixDiffs';
export const SNYK_FEATURE_FLAG_COMMAND = 'snyk.getFeatureFlagStatus';

// custom Snyk constants used in commands
export const SNYK_CONTEXT_PREFIX = 'snyk:';
3 changes: 3 additions & 0 deletions src/snyk/common/constants/featureFlags.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const FEATURE_FLAGS = {
consistentIgnores: 'snykCodeConsistentIgnores',
};
1 change: 1 addition & 0 deletions src/snyk/common/constants/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export const ADVANCED_ORGANIZATION = `${CONFIGURATION_IDENTIFIER}.advanced.organ
export const ADVANCED_AUTOMATIC_DEPENDENCY_MANAGEMENT = `${CONFIGURATION_IDENTIFIER}.advanced.automaticDependencyManagement`;
export const ADVANCED_CLI_PATH = `${CONFIGURATION_IDENTIFIER}.advanced.cliPath`;
export const ADVANCED_CUSTOM_LS_PATH = `${CONFIGURATION_IDENTIFIER}.advanced.languageServerPath`;
export const ADVANCED_ORGANIZATION_SETTING = `${CONFIGURATION_IDENTIFIER}.advanced.organization`;

export const SEVERITY_FILTER_SETTING = `${CONFIGURATION_IDENTIFIER}.severity`;
export const TRUSTED_FOLDERS = `${CONFIGURATION_IDENTIFIER}.trustedFolders`;
Expand Down
1 change: 1 addition & 0 deletions src/snyk/common/languageServer/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export type CodeIssueData = {
isSecurityType: boolean;
priorityScore: number;
hasAIFix: boolean;
details: string; // HTML from the LSP
};

export type ExampleCommitFix = {
Expand Down
5 changes: 5 additions & 0 deletions src/snyk/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,8 @@ export function languageToString(language: Language): string {
return PJSON;
}
}

export type FeatureFlagStatus = {
ok: boolean;
userMessage?: string;
};
6 changes: 6 additions & 0 deletions src/snyk/common/watchers/configurationWatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ import {
CODE_QUALITY_ENABLED_SETTING,
CODE_SECURITY_ENABLED_SETTING,
IAC_ENABLED_SETTING,
ADVANCED_ORGANIZATION_SETTING,
OSS_ENABLED_SETTING,
SEVERITY_FILTER_SETTING,
TRUSTED_FOLDERS,
} from '../constants/settings';
import { FEATURE_FLAGS } from '../constants/featureFlags';
import { ErrorHandler } from '../error/errorHandler';
import { ILog } from '../logger/interfaces';
import { errorsLogs } from '../messages/errors';
Expand All @@ -25,6 +27,9 @@ class ConfigurationWatcher implements IWatcher {
constructor(private readonly logger: ILog) {}

private async onChangeConfiguration(extension: IExtension, key: string): Promise<void> {
if (key === ADVANCED_ORGANIZATION_SETTING) {
await configuration.fetchAndSetFeatureFlag(FEATURE_FLAGS.consistentIgnores);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we not make this call for ADVANCED_ORGANIZATION so we don't need to add a new configuration key? We basically want to update the feature flag whenever the org changes right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check is for the settings page.

Is there another way to listen for a organisation change?

image

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm saying that I think ADVANCED_ORGANIZATION is already meant to represent a change for that panel: https://github.com/snyk/vscode-extension/blob/main/src/snyk/common/constants/settings.ts#L19. It looks like we're not listening to this in onChangeConfiguration though, for some weird reason.

What is the difference between ADVANCED_ORGANIZATION_SETTING and ADVANCED_ORGANIZATION?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh! I'm sorry! You were saying that I duplicated a variable!
You are right! I didn't realise I duplicated snyk-advanced.organization.
There is no difference, I made a mistake declaring a variable that already exists.
Deleting it now, thank you.

}
if (key === ADVANCED_ADVANCED_MODE_SETTING) {
return extension.checkAdvancedMode();
} else if (key === OSS_ENABLED_SETTING) {
Expand Down Expand Up @@ -63,6 +68,7 @@ class ConfigurationWatcher implements IWatcher {
const change = [
ADVANCED_ADVANCED_MODE_SETTING,
ADVANCED_AUTOSCAN_OSS_SETTING,
ADVANCED_ORGANIZATION_SETTING,
OSS_ENABLED_SETTING,
CODE_SECURITY_ENABLED_SETTING,
CODE_QUALITY_ENABLED_SETTING,
Expand Down
4 changes: 4 additions & 0 deletions src/snyk/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import {
SNYK_VIEW_SUPPORT,
SNYK_VIEW_WELCOME,
} from './common/constants/views';
import { FEATURE_FLAGS } from './common/constants/featureFlags';
import { ErrorHandler } from './common/error/errorHandler';
import { ErrorReporter } from './common/error/errorReporter';
import { ExperimentService } from './common/experiment/services/experimentService';
Expand Down Expand Up @@ -366,6 +367,9 @@ class SnykExtension extends SnykLib implements IExtension {
// The codeEnabled context depends on an LS command
await this.languageServer.start();

// Fetch feature flag to determine whether to use the new LSP-based rendering.
await configuration.fetchAndSetFeatureFlag(FEATURE_FLAGS.consistentIgnores);

// initialize contexts
await this.contextService.setContext(SNYK_CONTEXT.INITIALIZED, true);

Expand Down
1 change: 1 addition & 0 deletions src/test/unit/common/services/learnService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ suite('LearnService', () => {
isSecurityType: true,
priorityScore: 880,
hasAIFix: false,
details: 'not used',
},
title: 'not used',
severity: IssueSeverity.Critical,
Expand Down
Loading