From 194be064912813fb16a5d0f3e9a1ca3fa2d8a4d2 Mon Sep 17 00:00:00 2001 From: Tomas Vik Date: Tue, 13 Oct 2020 18:15:21 +0200 Subject: [PATCH] fix: select project dialog gets stuck in a perpetual loop --- .vscode/launch.json | 1 + src/data_providers/current_branch.js | 3 +- src/gitlab_service.js | 37 +------- src/openers.js | 17 ++-- src/pipeline_actions_picker.js | 3 +- src/search_input.js | 5 +- src/services/workspace_service.ts | 52 ++++++++++++ src/snippet_input.js | 3 +- src/status_bar.js | 6 +- .../services/workspace_service.test.js | 85 +++++++++++++++++++ 10 files changed, 161 insertions(+), 51 deletions(-) create mode 100644 src/services/workspace_service.ts create mode 100644 test/integration/services/workspace_service.test.js diff --git a/.vscode/launch.json b/.vscode/launch.json index 936b177..136d2c7 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -34,6 +34,7 @@ "--extensionTestsPath=${workspaceRoot}/out/test/integration/", "" ], + "preLaunchTask": "${defaultBuildTask}", "stopOnEntry": false } ] diff --git a/src/data_providers/current_branch.js b/src/data_providers/current_branch.js index 3b0bf7e..d8ccb02 100644 --- a/src/data_providers/current_branch.js +++ b/src/data_providers/current_branch.js @@ -3,6 +3,7 @@ const moment = require('moment'); const gitLabService = require('../gitlab_service'); const { SidebarTreeItem } = require('./sidebar_tree_item'); const ErrorItem = require('./error_item'); +const { getCurrentWorkspaceFolder } = require('../services/workspace_service'); class DataProvider { constructor() { @@ -94,7 +95,7 @@ class DataProvider { async getChildren() { try { - const workspaceFolder = await gitLabService.getCurrenWorkspaceFolder(); + const workspaceFolder = await getCurrentWorkspaceFolder(); this.project = await gitLabService.fetchCurrentProject(workspaceFolder); await this.fetchPipeline(workspaceFolder); await this.fetchMR(workspaceFolder); diff --git a/src/gitlab_service.js b/src/gitlab_service.js index 6428735..5ed6e25 100644 --- a/src/gitlab_service.js +++ b/src/gitlab_service.js @@ -4,8 +4,8 @@ const fs = require('fs'); const { GitService } = require('./git_service'); const tokenService = require('./token_service_wrapper'); const statusBar = require('./status_bar'); -const gitlabProjectInput = require('./gitlab_project_input'); const { ApiError, UserFriendlyError } = require('./errors'); +const { getCurrentWorkspaceFolder } = require('./services/workspace_service'); const projectCache = []; let versionCache = null; @@ -24,43 +24,12 @@ const createGitService = workspaceFolder => { }); }; -async function getCurrentWorkspaceFolder() { - const editor = vscode.window.activeTextEditor; - - if ( - editor && - editor.document && - vscode.workspace.getWorkspaceFolder(editor.document.uri) !== undefined - ) { - const workspaceFolder = vscode.workspace.getWorkspaceFolder(editor.document.uri).uri.fsPath; - return workspaceFolder; - } - - if (vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length === 1) { - return vscode.workspace.workspaceFolders[0].uri.fsPath; - } - - return null; -} - -async function getCurrentWorkspaceFolderOrSelectOne() { - let workspaceFolder = null; - - workspaceFolder = await getCurrentWorkspaceFolder(); - - if (workspaceFolder == null) { - workspaceFolder = await gitlabProjectInput.show(); - } - - return workspaceFolder; -} - async function fetch(path, method = 'GET', data = null) { const { ignoreCertificateErrors, ca, cert, certKey } = vscode.workspace.getConfiguration( 'gitlab', ); const instanceUrl = await createGitService( - await getCurrentWorkspaceFolderOrSelectOne(), + await getCurrentWorkspaceFolder(), ).fetchCurrentInstanceUrl(); const { proxy } = vscode.workspace.getConfiguration('http'); const apiRoot = `${instanceUrl}/api/v4`; @@ -682,8 +651,6 @@ exports.fetchVersion = fetchVersion; exports.fetchDiscussions = fetchDiscussions; exports.renderMarkdown = renderMarkdown; exports.saveNote = saveNote; -exports.getCurrentWorkspaceFolderOrSelectOne = getCurrentWorkspaceFolderOrSelectOne; exports.getAllGitlabProjects = getAllGitlabProjects; -exports.getCurrenWorkspaceFolder = getCurrentWorkspaceFolder; exports.fetchLabelEvents = fetchLabelEvents; exports.createGitService = createGitService; diff --git a/src/openers.js b/src/openers.js index f44c68c..a65bc61 100644 --- a/src/openers.js +++ b/src/openers.js @@ -2,6 +2,7 @@ const vscode = require('vscode'); const { GitService } = require('./git_service'); const gitLabService = require('./gitlab_service'); const tokenService = require('./token_service_wrapper'); +const { getCurrentWorkspaceFolderOrSelectOne } = require('./services/workspace_service'); const openUrl = url => vscode.commands.executeCommand('vscode.open', vscode.Uri.parse(url)); @@ -44,12 +45,12 @@ async function openLink(linkTemplate, workspaceFolder) { } async function showIssues() { - const workspaceFolder = await gitLabService.getCurrentWorkspaceFolderOrSelectOne(); + const workspaceFolder = await getCurrentWorkspaceFolderOrSelectOne(); await openLink('$projectUrl/issues?assignee_id=$userId', workspaceFolder); } async function showMergeRequests() { - const workspaceFolder = await gitLabService.getCurrentWorkspaceFolderOrSelectOne(); + const workspaceFolder = await getCurrentWorkspaceFolderOrSelectOne(); await openLink('$projectUrl/merge_requests?assignee_id=$userId', workspaceFolder); } @@ -95,7 +96,7 @@ async function copyLinkToActiveFile() { } async function openCurrentMergeRequest() { - const workspaceFolder = await gitLabService.getCurrentWorkspaceFolderOrSelectOne(); + const workspaceFolder = await getCurrentWorkspaceFolderOrSelectOne(); const mr = await gitLabService.fetchOpenMergeRequestForCurrentBranch(workspaceFolder); if (mr) { @@ -104,12 +105,12 @@ async function openCurrentMergeRequest() { } async function openCreateNewIssue() { - const workspaceFolder = await gitLabService.getCurrentWorkspaceFolderOrSelectOne(); + const workspaceFolder = await getCurrentWorkspaceFolderOrSelectOne(); openLink('$projectUrl/issues/new', workspaceFolder); } async function openCreateNewMr() { - const workspaceFolder = await gitLabService.getCurrentWorkspaceFolderOrSelectOne(); + const workspaceFolder = await getCurrentWorkspaceFolderOrSelectOne(); const project = await gitLabService.fetchCurrentProject(workspaceFolder); const branchName = await createGitService(workspaceFolder).fetchTrackingBranchName(); @@ -117,7 +118,7 @@ async function openCreateNewMr() { } async function openProjectPage() { - const workspaceFolder = await gitLabService.getCurrentWorkspaceFolderOrSelectOne(); + const workspaceFolder = await getCurrentWorkspaceFolderOrSelectOne(); openLink('$projectUrl', workspaceFolder); } @@ -125,7 +126,7 @@ async function openCurrentPipeline(workspaceFolder) { if (!workspaceFolder) { // Temporarily disable eslint to be able to start enforcing stricter rules // eslint-disable-next-line no-param-reassign - workspaceFolder = await gitLabService.getCurrentWorkspaceFolderOrSelectOne(); + workspaceFolder = await getCurrentWorkspaceFolderOrSelectOne(); } const project = await gitLabService.fetchCurrentPipelineProject(workspaceFolder); @@ -141,7 +142,7 @@ async function openCurrentPipeline(workspaceFolder) { async function compareCurrentBranch() { let project = null; let lastCommitId = null; - const workspaceFolder = await gitLabService.getCurrentWorkspaceFolderOrSelectOne(); + const workspaceFolder = await getCurrentWorkspaceFolderOrSelectOne(); project = await gitLabService.fetchCurrentProject(workspaceFolder); lastCommitId = await createGitService(workspaceFolder).fetchLastCommitId(); diff --git a/src/pipeline_actions_picker.js b/src/pipeline_actions_picker.js index 932bf0f..d0ee0a9 100644 --- a/src/pipeline_actions_picker.js +++ b/src/pipeline_actions_picker.js @@ -1,6 +1,7 @@ const vscode = require('vscode'); const gitLabService = require('./gitlab_service'); const openers = require('./openers'); +const { getCurrentWorkspaceFolderOrSelectOne } = require('./services/workspace_service'); async function showPicker() { const items = [ @@ -22,7 +23,7 @@ async function showPicker() { }, ]; - const workspaceFolder = await gitLabService.getCurrentWorkspaceFolderOrSelectOne(); + const workspaceFolder = await getCurrentWorkspaceFolderOrSelectOne(); const selected = await vscode.window.showQuickPick(items); diff --git a/src/search_input.js b/src/search_input.js index 5b98d09..f9f3e02 100644 --- a/src/search_input.js +++ b/src/search_input.js @@ -1,6 +1,7 @@ const vscode = require('vscode'); const gitLabService = require('./gitlab_service'); const openers = require('./openers'); +const { getCurrentWorkspaceFolderOrSelectOne } = require('./services/workspace_service'); const parseQuery = (query, noteableType) => { const params = {}; @@ -94,7 +95,7 @@ async function getSearchInput(description) { } async function showSearchInputFor(noteableType) { - const workspaceFolder = await gitLabService.getCurrentWorkspaceFolderOrSelectOne(); + const workspaceFolder = await getCurrentWorkspaceFolderOrSelectOne(); const project = await gitLabService.fetchCurrentProject(workspaceFolder); const query = await getSearchInput( 'Search in title or description. (Check extension page for search with filters)', @@ -113,7 +114,7 @@ async function showMergeRequestSearchInput() { } async function showProjectAdvancedSearchInput() { - const workspaceFolder = await gitLabService.getCurrentWorkspaceFolderOrSelectOne(); + const workspaceFolder = await getCurrentWorkspaceFolderOrSelectOne(); const project = await gitLabService.fetchCurrentProject(workspaceFolder); const query = await getSearchInput( 'Project Advanced Search. (Check extension page for Advanced Search)', diff --git a/src/services/workspace_service.ts b/src/services/workspace_service.ts new file mode 100644 index 0000000..5563fbf --- /dev/null +++ b/src/services/workspace_service.ts @@ -0,0 +1,52 @@ +import * as vscode from 'vscode'; + +async function getWorkspaceFolderForOpenEditor(): Promise { + const editor = vscode.window.activeTextEditor; + if (!editor?.document.uri) { + return undefined; + } + const workspaceFolder = vscode.workspace.getWorkspaceFolder(editor.document.uri); + return workspaceFolder?.uri.fsPath; +} + +export async function getCurrentWorkspaceFolder(): Promise { + const editorFolder = await getWorkspaceFolderForOpenEditor(); + + if (editorFolder) { + return editorFolder; + } + + const { workspaceFolders } = vscode.workspace; + if (workspaceFolders && workspaceFolders.length === 1) { + return workspaceFolders[0].uri.fsPath; + } + + return null; +} + +export async function getCurrentWorkspaceFolderOrSelectOne(): Promise { + const editorFolder = await getWorkspaceFolderForOpenEditor(); + + if (editorFolder) { + return editorFolder; + } + + const { workspaceFolders } = vscode.workspace; + if (!workspaceFolders || workspaceFolders.length === 0) { + return null; + } + if (workspaceFolders.length === 1) { + return workspaceFolders[0].uri.fsPath; + } + const workspaceFolderOptions = workspaceFolders.map(folder => ({ + label: folder.name, + uri: folder.uri.fsPath, + })); + const selectedFolder = await vscode.window.showQuickPick(workspaceFolderOptions, { + placeHolder: 'Select a workspace', + }); + if (selectedFolder) { + return selectedFolder.uri; + } + return null; +} diff --git a/src/snippet_input.js b/src/snippet_input.js index b8340fe..99a3052 100644 --- a/src/snippet_input.js +++ b/src/snippet_input.js @@ -2,6 +2,7 @@ const vscode = require('vscode'); const openers = require('./openers'); const gitLabService = require('./gitlab_service'); const gitlabProjectInput = require('./gitlab_project_input'); +const { getCurrentWorkspaceFolder } = require('./services/workspace_service'); const visibilityOptions = [ { @@ -67,7 +68,7 @@ async function showPicker() { let project = null; if (editor) { - workspaceFolder = await gitLabService.getCurrenWorkspaceFolder(); + workspaceFolder = await getCurrentWorkspaceFolder(); project = await gitLabService.fetchCurrentProjectSwallowError(workspaceFolder); if (project == null) { diff --git a/src/status_bar.js b/src/status_bar.js index 01da5a0..61df401 100644 --- a/src/status_bar.js +++ b/src/status_bar.js @@ -1,6 +1,7 @@ const vscode = require('vscode'); const openers = require('./openers'); const gitLabService = require('./gitlab_service'); +const { getCurrentWorkspaceFolder } = require('./services/workspace_service'); const { UserFriendlyError } = require('./errors'); let context = null; @@ -51,7 +52,7 @@ async function refreshPipeline() { }; try { - workspaceFolder = await gitLabService.getCurrenWorkspaceFolder(); + workspaceFolder = await getCurrentWorkspaceFolder(); project = await gitLabService.fetchCurrentPipelineProject(workspaceFolder); if (project != null) { pipeline = await gitLabService.fetchLastPipelineForCurrentBranch(workspaceFolder); @@ -139,13 +140,12 @@ async function fetchMRIssues(workspaceFolder) { } async function fetchBranchMR() { - const editor = vscode.window.activeTextEditor; let text = '$(git-pull-request) GitLab: No MR.'; let workspaceFolder = null; let project = null; try { - workspaceFolder = vscode.workspace.getWorkspaceFolder(editor.document.uri).uri.fsPath; + workspaceFolder = await getCurrentWorkspaceFolder(); project = await gitLabService.fetchCurrentProject(workspaceFolder); if (project != null) { mr = await gitLabService.fetchOpenMergeRequestForCurrentBranch(workspaceFolder); diff --git a/test/integration/services/workspace_service.test.js b/test/integration/services/workspace_service.test.js new file mode 100644 index 0000000..52e570c --- /dev/null +++ b/test/integration/services/workspace_service.test.js @@ -0,0 +1,85 @@ +const assert = require('assert'); +const sinon = require('sinon'); +const vscode = require('vscode'); +const workspaceService = require('../../../src/services/workspace_service'); + +describe('workspace_service', () => { + const sandbox = sinon.createSandbox(); + + describe('one workspace, no open files', () => { + it('getCurrentWorkspaceFolder returns workspace folder', async () => { + const result = await workspaceService.getCurrentWorkspaceFolder(); + assert.strictEqual(result, vscode.workspace.workspaceFolders[0].uri.fsPath); + }); + + it('getCurrentWorkspaceFolderOrSelectOne returns workspace folder', async () => { + const result = await workspaceService.getCurrentWorkspaceFolderOrSelectOne(); + assert.strictEqual(result, vscode.workspace.workspaceFolders[0].uri.fsPath); + }); + }); + + describe('multiple workspaces', () => { + const fakeFolders = [ + { + name: 'workspace 1', + uri: { fsPath: '/ws1' }, + }, + { + name: 'workspace 2', + uri: { fsPath: '/ws2' }, + }, + ]; + + let originalWorkspace; + + before(() => { + [originalWorkspace] = vscode.workspace.workspaceFolders; + sandbox.stub(vscode.workspace, 'workspaceFolders').get(() => fakeFolders); + }); + + after(() => { + sandbox.restore(); + }); + + it('getCurrentWorkspaceFolder returns null', async () => { + const result = await workspaceService.getCurrentWorkspaceFolder(); + assert.strictEqual(result, null); + }); + + it('getCurrentWorkspaceFolderOrSelectOne lets user select a workspace', async () => { + // simulating user selecting second option + sandbox.stub(vscode.window, 'showQuickPick').callsFake(async options => { + return options[1]; + }); + const result = await workspaceService.getCurrentWorkspaceFolderOrSelectOne(); + assert.strictEqual(result, '/ws2'); + }); + + describe('with open editor', () => { + let testFileUri; + beforeEach(async () => { + testFileUri = vscode.Uri.parse(`${originalWorkspace.uri.fsPath}/newfile.js`); + const createFileEdit = new vscode.WorkspaceEdit(); + createFileEdit.createFile(testFileUri); + await vscode.workspace.applyEdit(createFileEdit); + await vscode.window.showTextDocument(testFileUri); + }); + + afterEach(async () => { + const edit = new vscode.WorkspaceEdit(); + edit.deleteFile(testFileUri); + await vscode.workspace.applyEdit(edit); + }); + + it('getCurrentWorkspaceFolder returns workspace folder', async () => { + const result = await workspaceService.getCurrentWorkspaceFolder(); + assert.strictEqual(result, originalWorkspace.uri.fsPath); + }); + + it('getCurrentWorkspaceFolderOrSelectOne returns workspace folder', async () => { + const result = await workspaceService.getCurrentWorkspaceFolderOrSelectOne(); + assert.strictEqual(result, originalWorkspace.uri.fsPath); + }); + }); + }); +}); -- GitLab