Skip to content

Commit

Permalink
SLVSCODE-930 bring back the bind all workspace folders command
Browse files Browse the repository at this point in the history
  • Loading branch information
sophio-japharidze-sonarsource committed Nov 20, 2024
1 parent dcd9013 commit cb24c17
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 6 deletions.
58 changes: 55 additions & 3 deletions src/connected/autobinding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import { DONT_ASK_AGAIN_ACTION } from '../util/showMessage';
import * as vscode from 'vscode';
import { FileSystemSubscriber } from '../fileSystem/fileSystemSubscriber';
import { FileSystemServiceImpl } from '../fileSystem/fileSystemServiceImpl'
import { code2ProtocolConverter } from '../util/uri';
import { SonarLintExtendedLanguageClient } from '../lsp/client';

const AUTOBINDING_THRESHOLD = 1;
const BIND_ACTION = 'Configure Binding';
Expand All @@ -34,6 +36,10 @@ const CONFIGURE_BINDING_PROMPT_MESSAGE = `There are folders in your workspace th
Do you want to configure binding?
[Learn More](${SonarLintDocumentation.CONNECTED_MODE})`;

const CONFIGURE_BINDING_MANUALLY_PROMPT_MESSAGE = `SonarQube for IDE could not find any binding suggestions for SonarQube (Server, Cloud) projects.
Do you want to configure binding manually?
[Learn More](${SonarLintDocumentation.CONNECTED_MODE})`;

export class AutoBindingService implements FileSystemSubscriber {
private static _instance: AutoBindingService;
private readonly filesPerConfigScope : Map<string, FoundFileDto[]> = new Map<string, FoundFileDto[]>();
Expand All @@ -42,16 +48,18 @@ export class AutoBindingService implements FileSystemSubscriber {
bindingService: BindingService,
workspaceState: vscode.Memento,
settingsService: ConnectionSettingsService,
fileSystemService: FileSystemServiceImpl
fileSystemService: FileSystemServiceImpl,
languageClient: SonarLintExtendedLanguageClient
): void {
AutoBindingService._instance = new AutoBindingService(bindingService, workspaceState, settingsService);
AutoBindingService._instance = new AutoBindingService(bindingService, workspaceState, settingsService, languageClient);
fileSystemService.subscribe(AutoBindingService._instance);
}

constructor(
private readonly bindingService: BindingService,
private readonly workspaceState: vscode.Memento,
private readonly settingsService: ConnectionSettingsService,
private readonly languageClient: SonarLintExtendedLanguageClient
) {}

static get instance(): AutoBindingService {
Expand All @@ -77,6 +85,50 @@ export class AutoBindingService implements FileSystemSubscriber {
}
}

async autoBindWorkspace() {
if (vscode.workspace.workspaceFolders && this.isConnectionConfigured()) {
const unboundFolders = vscode.workspace.workspaceFolders.filter(
workspaceFolder => !this.bindingService.isBound(workspaceFolder)
);
if (unboundFolders.length > 0) {
const folderToBind = unboundFolders.length === 1 ? unboundFolders[0] : await this.selectFolderToBind(unboundFolders);
if (!folderToBind) {
return;
}
const configScopeId = code2ProtocolConverter(folderToBind.uri);
const targetConnection = await this.getTargetConnectionForManualBinding();
if (!targetConnection) {
return;
}
const connectionId = targetConnection.connectionId;
const suggestedBinding = await this.languageClient.getSuggestedBinding(configScopeId, connectionId);
if (suggestedBinding?.suggestions?.[configScopeId]) {
this.promptToAutoBind(suggestedBinding.suggestions[configScopeId], folderToBind);
}
} else {
vscode.window.showInformationMessage(`All folders in this workspace are already bound
to SonarQube (Server, Cloud) projects`);
}
} else if (!this.isConnectionConfigured()) {
vscode.window
.showWarningMessage(
`"Bind all workspace folders to SonarQube (Server, Cloud)"
can only be invoked if a SonarQube (Server, Cloud) connection exists`);
} else {
vscode.window.showWarningMessage(`"Bind all workspace folders to SonarQube (Server, Cloud)"
can only be invoked on an open workspace`);
}
}

private async selectFolderToBind(unboundFolders: vscode.WorkspaceFolder[]) : Promise<vscode.WorkspaceFolder> {
const folderNames = unboundFolders.map(folder => folder.name);
const folderNameToBind = await vscode.window.showQuickPick(folderNames, {
title: 'Select Folder to Bind',
placeHolder: 'Select the folder to bind to a SonarQube (Server, Cloud) project'
});
return unboundFolders.find(folder => folder.name === folderNameToBind);
}

private autoBindAllFolders(bindingSuggestions: { [folderUri: string]: Array<BindingSuggestion> }) {
const foldersNotToAutoBound = this.getFoldersThatShouldNotBeAutoBound();
Object.keys(bindingSuggestions).forEach((folderUri) => {
Expand Down Expand Up @@ -183,7 +235,7 @@ export class AutoBindingService implements FileSystemSubscriber {
private async promptToBindManually(unboundFolder: vscode.WorkspaceFolder) {
vscode.window
.showInformationMessage(
CONFIGURE_BINDING_PROMPT_MESSAGE,
CONFIGURE_BINDING_MANUALLY_PROMPT_MESSAGE,
BIND_ACTION,
DONT_ASK_AGAIN_ACTION
)
Expand Down
8 changes: 7 additions & 1 deletion src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ export async function activate(context: VSCode.ExtensionContext) {
FileSystemServiceImpl.init();
SharedConnectedModeSettingsService.init(languageClient, FileSystemServiceImpl.instance, context);
BindingService.init(languageClient, context.workspaceState, ConnectionSettingsService.instance, SharedConnectedModeSettingsService.instance);
AutoBindingService.init(BindingService.instance, context.workspaceState, ConnectionSettingsService.instance, FileSystemServiceImpl.instance);
AutoBindingService.init(BindingService.instance, context.workspaceState, ConnectionSettingsService.instance, FileSystemServiceImpl.instance, languageClient);
migrateConnectedModeSettings(getCurrentConfiguration(), ConnectionSettingsService.instance).catch(e => {
/* ignored */
});
Expand Down Expand Up @@ -444,6 +444,12 @@ function registerCommands(context: VSCode.ExtensionContext) {
VSCode.commands.registerCommand(Commands.CONFIGURE_COMPILATION_DATABASE, configureCompilationDatabase)
);

context.subscriptions.push(
VSCode.commands.registerCommand(Commands.AUTO_BIND_WORKSPACE_FOLDERS, () =>
AutoBindingService.instance.autoBindWorkspace()
)
);

context.subscriptions.push(
VSCode.commands.registerCommand(Commands.CONNECT_TO_SONARQUBE, () => connectToSonarQube(context)())
);
Expand Down
1 change: 1 addition & 0 deletions src/util/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,5 @@ export namespace Commands {
export const ENABLE_VERBOSE_LOGS = 'SonarLint.EnableVerboseLogs';
export const ANALYSE_OPEN_FILE = 'SonarLint.AnalyseOpenFile';
export const NEW_CODE_DEFINITION = 'SonarLint.NewCodeDefinition';
export const AUTO_BIND_WORKSPACE_FOLDERS = 'SonarLint.AutoBindWorkspaceFolders';
}
21 changes: 19 additions & 2 deletions test/suite/autobinding.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ import * as VSCode from 'vscode';
import { expect } from 'chai';
import { AutoBindingService, DO_NOT_ASK_ABOUT_AUTO_BINDING_FOR_WS_FLAG } from '../../src/connected/autobinding';
import { TextEncoder } from 'util';
import { FolderUriParams, ListFilesInScopeResponse } from '../../src/lsp/protocol';
import { FolderUriParams, ListFilesInScopeResponse, SuggestBindingParams } from '../../src/lsp/protocol';
import { FileSystemServiceImpl } from '../../src/fileSystem/fileSystemServiceImpl';
import { sleep } from '../testutil';
import { SonarLintExtendedLanguageClient } from '../../src/lsp/client';

const CONNECTED_MODE_SETTINGS_SONARQUBE = 'connectedMode.connections.sonarqube';
const CONNECTED_MODE_SETTINGS_SONARCLOUD = 'connectedMode.connections.sonarcloud';
Expand All @@ -33,6 +34,21 @@ const TEST_SONARQUBE_CONNECTION = {
serverUrl: 'https://test.sonarqube.com'
};

const mockClient = {
async getRemoteProjectsForConnection(_connectionId: string): Promise<Object> {
return { projectKey1: 'projectName1', projectKey2: 'projectName2' };
},
async checkConnection(connectionId: string) {
return Promise.resolve({ connectionId, success: true });
},
async getSuggestedBinding(configScopeId:string, connectionId: string):Promise<SuggestBindingParams> {
return Promise.resolve({suggestions:{}});
},
async didCreateBinding(mode) {
return Promise.resolve();
}
} as SonarLintExtendedLanguageClient;

const mockSettingsService = {
async loadSonarQubeConnection(connectionId: string): Promise<SonarQubeConnection> {
return { serverUrl: 'https://next.sonarqube.com/sonarqube', connectionId };
Expand Down Expand Up @@ -113,7 +129,8 @@ suite('Auto Binding Test Suite', () => {
mockBindingService,
mockWorkspaceState,
mockSettingsService,
FileSystemServiceImpl.instance
FileSystemServiceImpl.instance,
mockClient
);
underTest = AutoBindingService.instance;
});
Expand Down

0 comments on commit cb24c17

Please sign in to comment.