提交 4fbd4cae 编写于 作者: T Tomas Vik

Merge branch '129-prepare-token-and-workspace' into 'main'

Untangle the workspace and token related logic

Closes #239

See merge request gitlab-org/gitlab-vscode-extension!114
......@@ -34,6 +34,7 @@
"--extensionTestsPath=${workspaceRoot}/out/test/integration/",
"<paste the last line of `npm run create-test-workspace` output here>"
],
"preLaunchTask": "${defaultBuildTask}",
"stopOnEntry": false
}
]
......
......@@ -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);
......
const vscode = require('vscode');
const openers = require('./openers');
const tokenInput = require('./token_input');
const tokenService = require('./token_service');
const { tokenService } = require('./services/token_service');
const tokenServiceWrapper = require('./token_service_wrapper');
const pipelineActionsPicker = require('./pipeline_actions_picker');
const searchInput = require('./search_input');
const snippetInput = require('./snippet_input');
......@@ -85,6 +86,7 @@ const activate = context => {
registerCommands(context, outputChannel);
webviewController.addDeps(context);
tokenService.init(context);
tokenServiceWrapper.init(context);
};
exports.activate = activate;
......@@ -2,10 +2,10 @@ const vscode = require('vscode');
const request = require('request-promise');
const fs = require('fs');
const { GitService } = require('./git_service');
const tokenService = require('./token_service');
const { tokenService } = require('./services/token_service');
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;
const vscode = require('vscode');
const { GitService } = require('./git_service');
const gitLabService = require('./gitlab_service');
const tokenService = require('./token_service');
const { tokenService } = require('./services/token_service');
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();
......
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);
......
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)',
......
import * as assert from 'assert';
import { EventEmitter, ExtensionContext, Event } from 'vscode';
export class TokenService {
context?: ExtensionContext;
private onDidChangeEmitter = new EventEmitter<void>();
init(context: ExtensionContext) {
this.context = context;
}
get onDidChange(): Event<void> {
return this.onDidChangeEmitter.event;
}
private get glTokenMap() {
assert(this.context);
return this.context.globalState.get<Record<string, string>>('glTokens', {});
}
getInstanceUrls() {
return Object.keys(this.glTokenMap);
}
getToken(instanceUrl: string) {
return this.glTokenMap[instanceUrl];
}
setToken(instanceUrl: string, token: string | undefined) {
assert(this.context);
const tokenMap = this.glTokenMap;
if (token) {
tokenMap[instanceUrl] = token;
} else {
delete tokenMap[instanceUrl];
}
this.context.globalState.update('glTokens', tokenMap);
this.onDidChangeEmitter.fire();
}
}
export const tokenService: TokenService = new TokenService();
import * as vscode from 'vscode';
async function getWorkspaceFolderForOpenEditor(): Promise<string | undefined> {
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<string | null> {
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<string | null> {
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;
}
......@@ -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) {
......
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);
......
const vscode = require('vscode');
const { GITLAB_COM_URL } = require('./constants');
const tokenService = require('./token_service');
const { tokenService } = require('./services/token_service');
async function showInput() {
const instance = await vscode.window.showInputBox({
......
......@@ -2,6 +2,7 @@ const vscode = require('vscode');
const { GITLAB_COM_URL } = require('./constants');
const openers = require('./openers');
const statusBar = require('./status_bar');
const { tokenService } = require('./services/token_service');
let context = null;
let active = false;
......@@ -9,11 +10,7 @@ let active = false;
const currentInstanceUrl = () =>
vscode.workspace.getConfiguration('gitlab').instanceUrl || GITLAB_COM_URL;
const getGlTokenMap = () => context.globalState.get('glTokens', {});
const getToken = (instanceUrl = currentInstanceUrl()) => getGlTokenMap()[instanceUrl];
const getInstanceUrls = () => Object.keys(getGlTokenMap());
const getToken = (instanceUrl = currentInstanceUrl()) => tokenService.getToken(instanceUrl);
const updateExtensionStatus = () => {
const tokenExists = !!getToken();
......@@ -27,33 +24,6 @@ const updateExtensionStatus = () => {
}
};
const setToken = (instanceUrl, token) => {
const tokenMap = getGlTokenMap();
if (token) {
tokenMap[instanceUrl] = token;
} else {
delete tokenMap[instanceUrl];
}
context.globalState.update('glTokens', tokenMap);
updateExtensionStatus();
};
const migrateLegacyToken = () => {
const token = context.globalState.get('glToken');
if (token) {
const instanceUrl = currentInstanceUrl();
if (!getToken(instanceUrl)) {
setToken(instanceUrl, token);
}
context.globalState.update('glToken', null);
}
};
const askForToken = () => {
if (!getToken() && !context.workspaceState.get('askedForToken')) {
const message =
......@@ -86,14 +56,10 @@ const watchConfigurationChanges = () => {
const init = ctx => {
context = ctx;
migrateLegacyToken();
tokenService.onDidChange(() => updateExtensionStatus());
askForToken();
updateExtensionStatus();
watchConfigurationChanges();
};
exports.init = init;
exports.getToken = getToken;
exports.setToken = setToken;
exports.getInstanceUrls = getInstanceUrls;
const assert = require('assert');
const { TokenService } = require('../../../src/services/token_service');
describe('TokenService', () => {
let tokenService;
beforeEach(() => {
let tokens = {};
const fakeContext = {
globalState: {
get: () => tokens,
update: (_, val) => {
tokens = val;
},
},
};
tokenService = new TokenService();
tokenService.init(fakeContext);
});
it('can set and get one token', async () => {
assert.strictEqual(tokenService.getToken('https://gitlab.com'), undefined);
tokenService.setToken('https://gitlab.com', 'abc');
assert.strictEqual(tokenService.getToken('https://gitlab.com'), 'abc');
});
it('can retrieve all instance URLs', async () => {
tokenService.setToken('https://gitlab.com', 'abc');
tokenService.setToken('https://dev.gitlab.com', 'def');
assert.deepStrictEqual(tokenService.getInstanceUrls(), [
'https://gitlab.com',
'https://dev.gitlab.com',
]);
});
});
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);
});
});
});
});
......@@ -2,7 +2,7 @@ const assert = require('assert');
const sinon = require('sinon');
const vscode = require('vscode');
const statusBar = require('../../src/status_bar');
const tokenService = require('../../src/token_service');
const { tokenService } = require('../../src/services/token_service');
const getServer = require('./test_infrastructure/mock_server');
const { GITLAB_HOST } = require('./test_infrastructure/constants');
......@@ -35,6 +35,7 @@ describe('GitLab status bar', () => {
after(() => {
server.close();
tokenService.setToken(`https://${GITLAB_HOST}`, undefined);
});
it('shows the correct pipeline item', async () => {
......
const assert = require('assert');
const IssuableDataProvider = require('../../src/data_providers/issuable').DataProvider;
const tokenService = require('../../src/token_service');
const { tokenService } = require('../../src/services/token_service');
const getServer = require('./test_infrastructure/mock_server');
const { GITLAB_HOST } = require('./test_infrastructure/constants');
......@@ -20,6 +20,7 @@ describe('GitLab tree view', () => {
after(() => {
server.close();
tokenService.setToken(`https://${GITLAB_HOST}`, undefined);
});
/**
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册