提交 457ca510 编写于 作者: M Murad Yusufov 提交者: Tomas Vik

feat: detect instanceUrl from git remotes and GitLab access tokens

find the intersection of git remotes hostnames and PATs hostnames,
and if the intersection has exactly one hostname,
use that as the instanceUrl, otherwise just do nothing.
上级 a4e30e47
......@@ -148,8 +148,8 @@
"title": "GitLab Workflow (GitLab VSCode Extension)",
"properties": {
"gitlab.instanceUrl": {
"type": "string",
"default": "https://gitlab.com",
"type": ["string", "null"],
"default": null,
"description": "Your GitLab instance URL (default is https://gitlab.com)"
},
"gitlab.showStatusBarLinks": {
......
......@@ -24,6 +24,10 @@ function parseGitRemote(instanceUrl, remote) {
return null;
}
if (!instanceUrl) {
return [protocol, host, pathname];
}
const pathRegExp = escapeForRegExp(getInstancePath(instanceUrl));
const match = pathname.match(`${pathRegExp}/:?(.+)/(.*?)(?:.git)?$`);
if (!match) {
......
const vscode = require('vscode');
const execa = require('execa');
const url = require('url');
const tokenService = require('./token_service');
const { parseGitRemote } = require('./git/git_remote_parser');
const currentInstanceUrl = () => vscode.workspace.getConfiguration('gitlab').instanceUrl;
async function fetch(cmd, workspaceFolder) {
const [git, ...args] = cmd.trim().split(' ');
let currentWorkspaceFolder = workspaceFolder;
......@@ -24,6 +24,82 @@ async function fetch(cmd, workspaceFolder) {
return output;
}
const fetchGitRemoteUrls = async workspaceFolder => {
const fetchGitRemotesVerbose = async () => {
const cmd = 'git remote -v';
const output = await fetch(cmd, workspaceFolder);
return output.split('\n');
};
const parseRemoteFromVerboseLine = line => {
// git remote -v output looks like
// origin[TAB]git@gitlab.com:gitlab-org/gitlab-vscode-extension.git[WHITESPACE](fetch)
// the interesting part is surrounded by a tab symbol and a whitespace
return line.split(/\t| /)[1];
};
const remotes = await fetchGitRemotesVerbose();
const remoteUrls = remotes.map(remote => parseRemoteFromVerboseLine(remote));
// git remote -v returns a (fetch) and a (push) line for each remote,
// so we need to remove duplicates
return [...new Set(remoteUrls)];
};
const intersectionOfInstanceAndTokenUrls = async workspaceFolder => {
const uriHostname = uri => url.parse(uri).host;
const instanceUrls = tokenService.getInstanceUrls();
const gitRemotes = await fetchGitRemoteUrls(workspaceFolder);
const gitRemoteHosts = gitRemotes.map(remote => {
const [, host] = parseGitRemote(null, remote);
return host;
});
return instanceUrls.filter(host => gitRemoteHosts.includes(uriHostname(host)));
};
const heuristicInstanceUrl = async workspaceFolder => {
// if the intersection of git remotes and configured PATs exists and is exactly
// one hostname, use it
const intersection = await intersectionOfInstanceAndTokenUrls(workspaceFolder);
if (intersection.length === 1) {
const heuristicUrl = intersection[0];
console.log(
`Found ${heuristicUrl} in the PAT list and git remotes, using it as the instanceUrl`,
);
return heuristicUrl;
}
if (intersection.length > 1) {
console.log(
'Found more than one intersection of git remotes and configured PATs',
intersection,
);
}
return null;
};
const fetchCurrentInstanceUrl = async workspaceFolder => {
// if the workspace setting exists, use it
const workspaceInstanceUrl = vscode.workspace.getConfiguration('gitlab').instanceUrl;
if (workspaceInstanceUrl) {
return workspaceInstanceUrl;
}
// try to determine the instance URL heuristically
const heuristicUrl = await heuristicInstanceUrl(workspaceFolder);
if (heuristicUrl) {
return heuristicUrl;
}
// default to Gitlab cloud
return 'https://gitlab.com';
};
async function fetchBranchName(workspaceFolder) {
const cmd = 'git rev-parse --abbrev-ref HEAD';
const output = await fetch(cmd, workspaceFolder);
......@@ -65,7 +141,7 @@ async function fetchLastCommitId(workspaceFolder) {
}
async function fetchRemoteUrl(remoteName, workspaceFolder) {
// If remote name isn't provided, we the command returns default remote for the current branch
// If remote name isn't provided, the command returns default remote for the current branch
const getUrlForRemoteName = async name =>
fetch(`git ls-remote --get-url ${name || ''}`, workspaceFolder);
......@@ -81,7 +157,8 @@ async function fetchRemoteUrl(remoteName, workspaceFolder) {
}
if (remoteUrl) {
const [schema, host, namespace, project] = parseGitRemote(currentInstanceUrl(), remoteUrl);
const instanceUrl = await fetchCurrentInstanceUrl(workspaceFolder);
const [schema, host, namespace, project] = parseGitRemote(instanceUrl, remoteUrl);
return { schema, host, namespace, project };
}
......@@ -106,3 +183,4 @@ exports.fetchTrackingBranchName = fetchTrackingBranchName;
exports.fetchLastCommitId = fetchLastCommitId;
exports.fetchGitRemote = fetchGitRemote;
exports.fetchGitRemotePipeline = fetchGitRemotePipeline;
exports.fetchCurrentInstanceUrl = fetchCurrentInstanceUrl;
......@@ -9,14 +9,44 @@ const gitlabProjectInput = require('./gitlab_project_input');
const projectCache = [];
let versionCache = null;
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 {
instanceUrl,
ignoreCertificateErrors,
ca,
cert,
certKey,
} = vscode.workspace.getConfiguration('gitlab');
const { ignoreCertificateErrors, ca, cert, certKey } = vscode.workspace.getConfiguration(
'gitlab',
);
const instanceUrl = await gitService.fetchCurrentInstanceUrl(
await getCurrentWorkspaceFolderOrSelectOne(),
);
const { proxy } = vscode.workspace.getConfiguration('http');
const apiRoot = `${instanceUrl}/api/v4`;
const glToken = tokenService.getToken(instanceUrl);
......@@ -623,37 +653,6 @@ async function saveNote({ issuable, note, noteType }) {
return { success: false };
}
async function getCurrenWorkspaceFolder() {
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;
const project = await fetchCurrentProject(workspaceFolder);
if (project != null) {
return workspaceFolder;
}
} else 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 getCurrenWorkspaceFolder();
if (workspaceFolder == null) {
workspaceFolder = await gitlabProjectInput.show();
}
return workspaceFolder;
}
exports.fetchCurrentUser = fetchCurrentUser;
exports.fetchIssuables = fetchIssuables;
exports.fetchOpenMergeRequestForCurrentBranch = fetchOpenMergeRequestForCurrentBranch;
......@@ -671,5 +670,5 @@ exports.renderMarkdown = renderMarkdown;
exports.saveNote = saveNote;
exports.getCurrentWorkspaceFolderOrSelectOne = getCurrentWorkspaceFolderOrSelectOne;
exports.getAllGitlabProjects = getAllGitlabProjects;
exports.getCurrenWorkspaceFolder = getCurrenWorkspaceFolder;
exports.getCurrenWorkspaceFolder = getCurrentWorkspaceFolder;
exports.fetchLabelEvents = fetchLabelEvents;
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册