mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-12 19:18:32 -05:00
Merge from vscode 2e5312cd61ff99c570299ecc122c52584265eda2
This commit is contained in:
committed by
Anthony Dresser
parent
3603f55d97
commit
7f1d8fc32f
122
src/vs/platform/extensionManagement/common/configRemotes.ts
Normal file
122
src/vs/platform/extensionManagement/common/configRemotes.ts
Normal file
@@ -0,0 +1,122 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { endsWith } from 'vs/base/common/strings';
|
||||
|
||||
const SshProtocolMatcher = /^([^@:]+@)?([^:]+):/;
|
||||
const SshUrlMatcher = /^([^@:]+@)?([^:]+):(.+)$/;
|
||||
const AuthorityMatcher = /^([^@]+@)?([^:]+)(:\d+)?$/;
|
||||
const SecondLevelDomainMatcher = /([^@:.]+\.[^@:.]+)(:\d+)?$/;
|
||||
const RemoteMatcher = /^\s*url\s*=\s*(.+\S)\s*$/mg;
|
||||
const AnyButDot = /[^.]/g;
|
||||
|
||||
export const SecondLevelDomainWhitelist = [
|
||||
'github.com',
|
||||
'bitbucket.org',
|
||||
'visualstudio.com',
|
||||
'gitlab.com',
|
||||
'heroku.com',
|
||||
'azurewebsites.net',
|
||||
'ibm.com',
|
||||
'amazon.com',
|
||||
'amazonaws.com',
|
||||
'cloudapp.net',
|
||||
'rhcloud.com',
|
||||
'google.com',
|
||||
'azure.com'
|
||||
];
|
||||
|
||||
function stripLowLevelDomains(domain: string): string | null {
|
||||
const match = domain.match(SecondLevelDomainMatcher);
|
||||
return match ? match[1] : null;
|
||||
}
|
||||
|
||||
function extractDomain(url: string): string | null {
|
||||
if (url.indexOf('://') === -1) {
|
||||
const match = url.match(SshProtocolMatcher);
|
||||
if (match) {
|
||||
return stripLowLevelDomains(match[2]);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
try {
|
||||
const uri = URI.parse(url);
|
||||
if (uri.authority) {
|
||||
return stripLowLevelDomains(uri.authority);
|
||||
}
|
||||
} catch (e) {
|
||||
// ignore invalid URIs
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function getDomainsOfRemotes(text: string, whitelist: string[]): string[] {
|
||||
const domains = new Set<string>();
|
||||
let match: RegExpExecArray | null;
|
||||
while (match = RemoteMatcher.exec(text)) {
|
||||
const domain = extractDomain(match[1]);
|
||||
if (domain) {
|
||||
domains.add(domain);
|
||||
}
|
||||
}
|
||||
|
||||
const whitemap = whitelist.reduce((map, key) => {
|
||||
map[key] = true;
|
||||
return map;
|
||||
}, Object.create(null));
|
||||
|
||||
const elements: string[] = [];
|
||||
domains.forEach(e => elements.push(e));
|
||||
|
||||
return elements
|
||||
.map(key => whitemap[key] ? key : key.replace(AnyButDot, 'a'));
|
||||
}
|
||||
|
||||
function stripPort(authority: string): string | null {
|
||||
const match = authority.match(AuthorityMatcher);
|
||||
return match ? match[2] : null;
|
||||
}
|
||||
|
||||
function normalizeRemote(host: string | null, path: string, stripEndingDotGit: boolean): string | null {
|
||||
if (host && path) {
|
||||
if (stripEndingDotGit && endsWith(path, '.git')) {
|
||||
path = path.substr(0, path.length - 4);
|
||||
}
|
||||
return (path.indexOf('/') === 0) ? `${host}${path}` : `${host}/${path}`;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function extractRemote(url: string, stripEndingDotGit: boolean): string | null {
|
||||
if (url.indexOf('://') === -1) {
|
||||
const match = url.match(SshUrlMatcher);
|
||||
if (match) {
|
||||
return normalizeRemote(match[2], match[3], stripEndingDotGit);
|
||||
}
|
||||
}
|
||||
try {
|
||||
const uri = URI.parse(url);
|
||||
if (uri.authority) {
|
||||
return normalizeRemote(stripPort(uri.authority), uri.path, stripEndingDotGit);
|
||||
}
|
||||
} catch (e) {
|
||||
// ignore invalid URIs
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function getRemotes(text: string, stripEndingDotGit: boolean = false): string[] {
|
||||
const remotes: string[] = [];
|
||||
let match: RegExpExecArray | null;
|
||||
while (match = RemoteMatcher.exec(text)) {
|
||||
const remote = extractRemote(match[1], stripEndingDotGit);
|
||||
if (remote) {
|
||||
remotes.push(remote);
|
||||
}
|
||||
}
|
||||
return remotes;
|
||||
}
|
||||
@@ -226,6 +226,13 @@ export interface IGlobalExtensionEnablementService {
|
||||
|
||||
}
|
||||
|
||||
export type IConfigBasedExtensionTip = {
|
||||
readonly extensionId: string,
|
||||
readonly extensionName: string,
|
||||
readonly isExtensionPack: boolean,
|
||||
readonly configName: string,
|
||||
readonly important: boolean,
|
||||
};
|
||||
export type IExecutableBasedExtensionTip = { extensionId: string } & Omit<Omit<IExeBasedExtensionTip, 'recommendations'>, 'important'>;
|
||||
export type IWorkspaceTips = { readonly remoteSet: string[]; readonly recommendations: string[]; };
|
||||
|
||||
@@ -233,6 +240,7 @@ export const IExtensionTipsService = createDecorator<IExtensionTipsService>('IEx
|
||||
export interface IExtensionTipsService {
|
||||
_serviceBrand: undefined;
|
||||
|
||||
getConfigBasedTips(folder: URI): Promise<IConfigBasedExtensionTip[]>;
|
||||
getImportantExecutableBasedTips(): Promise<IExecutableBasedExtensionTip[]>;
|
||||
getOtherExecutableBasedTips(): Promise<IExecutableBasedExtensionTip[]>;
|
||||
getAllWorkspacesTips(): Promise<IWorkspaceTips[]>;
|
||||
|
||||
@@ -142,6 +142,7 @@ export class ExtensionTipsChannel implements IServerChannel {
|
||||
|
||||
call(context: any, command: string, args?: any): Promise<any> {
|
||||
switch (command) {
|
||||
case 'getConfigBasedTips': return this.service.getConfigBasedTips(URI.revive(args[0]));
|
||||
case 'getImportantExecutableBasedTips': return this.service.getImportantExecutableBasedTips();
|
||||
case 'getOtherExecutableBasedTips': return this.service.getOtherExecutableBasedTips();
|
||||
case 'getAllWorkspacesTips': return this.service.getAllWorkspacesTips();
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IProductService, IConfigBasedExtensionTip as IRawConfigBasedExtensionTip } from 'vs/platform/product/common/productService';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { isNonEmptyArray } from 'vs/base/common/arrays';
|
||||
import { IExtensionTipsService, IExecutableBasedExtensionTip, IWorkspaceTips, IConfigBasedExtensionTip } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { forEach } from 'vs/base/common/collections';
|
||||
import { IRequestService, asJson } from 'vs/platform/request/common/request';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { joinPath } from 'vs/base/common/resources';
|
||||
import { getDomainsOfRemotes } from 'vs/platform/extensionManagement/common/configRemotes';
|
||||
import { keys } from 'vs/base/common/map';
|
||||
|
||||
export class ExtensionTipsService implements IExtensionTipsService {
|
||||
|
||||
_serviceBrand: any;
|
||||
|
||||
private readonly allConfigBasedTips: Map<string, IRawConfigBasedExtensionTip> = new Map<string, IRawConfigBasedExtensionTip>();
|
||||
|
||||
constructor(
|
||||
@IFileService protected readonly fileService: IFileService,
|
||||
@IProductService private readonly productService: IProductService,
|
||||
@IRequestService private readonly requestService: IRequestService,
|
||||
@ILogService private readonly logService: ILogService,
|
||||
) {
|
||||
if (this.productService.configBasedExtensionTips) {
|
||||
forEach(this.productService.configBasedExtensionTips, ({ value }) => this.allConfigBasedTips.set(value.configPath, value));
|
||||
}
|
||||
}
|
||||
|
||||
getConfigBasedTips(folder: URI): Promise<IConfigBasedExtensionTip[]> {
|
||||
return this.getValidConfigBasedTips(folder);
|
||||
}
|
||||
|
||||
getAllWorkspacesTips(): Promise<IWorkspaceTips[]> {
|
||||
return this.fetchWorkspacesTips();
|
||||
}
|
||||
|
||||
async getImportantExecutableBasedTips(): Promise<IExecutableBasedExtensionTip[]> {
|
||||
return [];
|
||||
}
|
||||
|
||||
async getOtherExecutableBasedTips(): Promise<IExecutableBasedExtensionTip[]> {
|
||||
return [];
|
||||
}
|
||||
|
||||
private async getValidConfigBasedTips(folder: URI): Promise<IConfigBasedExtensionTip[]> {
|
||||
const result: IConfigBasedExtensionTip[] = [];
|
||||
for (const [configPath, tip] of this.allConfigBasedTips) {
|
||||
try {
|
||||
const content = await this.fileService.readFile(joinPath(folder, configPath));
|
||||
const recommendationByRemote: Map<string, IConfigBasedExtensionTip> = new Map<string, IConfigBasedExtensionTip>();
|
||||
forEach(tip.recommendations, ({ key, value }) => {
|
||||
if (isNonEmptyArray(value.remotes)) {
|
||||
for (const remote of value.remotes) {
|
||||
recommendationByRemote.set(remote, {
|
||||
extensionId: key,
|
||||
extensionName: value.name,
|
||||
configName: tip.configName,
|
||||
important: !!value.important,
|
||||
isExtensionPack: !!value.isExtensionPack
|
||||
});
|
||||
}
|
||||
} else {
|
||||
result.push({
|
||||
extensionId: key,
|
||||
extensionName: value.name,
|
||||
configName: tip.configName,
|
||||
important: !!value.important,
|
||||
isExtensionPack: !!value.isExtensionPack
|
||||
});
|
||||
}
|
||||
});
|
||||
const remotes = getDomainsOfRemotes(content.value.toString(), keys(recommendationByRemote));
|
||||
remotes.forEach(remote => result.push(recommendationByRemote.get(remote)!));
|
||||
} catch (error) { /* Ignore */ }
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private async fetchWorkspacesTips(): Promise<IWorkspaceTips[]> {
|
||||
if (!this.productService.extensionsGallery?.recommendationsUrl) {
|
||||
return [];
|
||||
}
|
||||
try {
|
||||
const context = await this.requestService.request({ type: 'GET', url: this.productService.extensionsGallery?.recommendationsUrl }, CancellationToken.None);
|
||||
if (context.res.statusCode !== 200) {
|
||||
return [];
|
||||
}
|
||||
const result = await asJson<{ workspaceRecommendations?: IWorkspaceTips[] }>(context);
|
||||
if (!result) {
|
||||
return [];
|
||||
}
|
||||
return result.workspaceRecommendations || [];
|
||||
} catch (error) {
|
||||
this.logService.error(error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -771,7 +771,6 @@ export class ExtensionManagementService extends Disposable implements IExtension
|
||||
// Scan other system extensions during development
|
||||
const devSystemExtensionsPromise = this.getDevSystemExtensionsList()
|
||||
.then(devSystemExtensionsList => {
|
||||
console.log(devSystemExtensionsList);
|
||||
if (devSystemExtensionsList.length) {
|
||||
return this.scanExtensions(this.devSystemExtensionsPath, ExtensionType.System)
|
||||
.then(result => {
|
||||
|
||||
@@ -12,13 +12,13 @@ import { INativeEnvironmentService } from 'vs/platform/environment/node/environm
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { isWindows } from 'vs/base/common/platform';
|
||||
import { isNonEmptyArray } from 'vs/base/common/arrays';
|
||||
import { IExtensionTipsService, IExecutableBasedExtensionTip, IWorkspaceTips } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { IExecutableBasedExtensionTip } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { IStringDictionary, forEach } from 'vs/base/common/collections';
|
||||
import { IRequestService, asJson } from 'vs/platform/request/common/request';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IRequestService } from 'vs/platform/request/common/request';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { ExtensionTipsService as BaseExtensionTipsService } from 'vs/platform/extensionManagement/common/extensionTipsService';
|
||||
|
||||
export class ExtensionTipsService implements IExtensionTipsService {
|
||||
export class ExtensionTipsService extends BaseExtensionTipsService {
|
||||
|
||||
_serviceBrand: any;
|
||||
|
||||
@@ -26,14 +26,15 @@ export class ExtensionTipsService implements IExtensionTipsService {
|
||||
private readonly allOtherExecutableTips: IStringDictionary<IExeBasedExtensionTip> = {};
|
||||
|
||||
constructor(
|
||||
@IFileService private readonly fileService: IFileService,
|
||||
@IEnvironmentService private readonly environmentService: IEnvironmentService,
|
||||
@IProductService private readonly productService: IProductService,
|
||||
@IRequestService private readonly requestService: IRequestService,
|
||||
@ILogService private readonly logService: ILogService,
|
||||
@IEnvironmentService private readonly environmentService: INativeEnvironmentService,
|
||||
@IFileService fileService: IFileService,
|
||||
@IProductService productService: IProductService,
|
||||
@IRequestService requestService: IRequestService,
|
||||
@ILogService logService: ILogService,
|
||||
) {
|
||||
if (this.productService.exeBasedExtensionTips) {
|
||||
forEach(this.productService.exeBasedExtensionTips, ({ key, value }) => {
|
||||
super(fileService, productService, requestService, logService);
|
||||
if (productService.exeBasedExtensionTips) {
|
||||
forEach(productService.exeBasedExtensionTips, ({ key, value }) => {
|
||||
if (value.important) {
|
||||
this.allImportantExecutableTips[key] = value;
|
||||
} else {
|
||||
@@ -43,10 +44,6 @@ export class ExtensionTipsService implements IExtensionTipsService {
|
||||
}
|
||||
}
|
||||
|
||||
getAllWorkspacesTips(): Promise<IWorkspaceTips[]> {
|
||||
return this.fetchWorkspacesTips();
|
||||
}
|
||||
|
||||
getImportantExecutableBasedTips(): Promise<IExecutableBasedExtensionTip[]> {
|
||||
return this.getValidExecutableBasedExtensionTips(this.allImportantExecutableTips);
|
||||
}
|
||||
@@ -76,7 +73,7 @@ export class ExtensionTipsService implements IExtensionTipsService {
|
||||
}
|
||||
} else {
|
||||
exePaths.push(join('/usr/local/bin', exeName));
|
||||
exePaths.push(join((this.environmentService as INativeEnvironmentService).userHome.fsPath, exeName));
|
||||
exePaths.push(join(this.environmentService.userHome.fsPath, exeName));
|
||||
}
|
||||
|
||||
for (const exePath of exePaths) {
|
||||
@@ -99,24 +96,4 @@ export class ExtensionTipsService implements IExtensionTipsService {
|
||||
return result;
|
||||
}
|
||||
|
||||
private async fetchWorkspacesTips(): Promise<IWorkspaceTips[]> {
|
||||
if (!this.productService.extensionsGallery?.recommendationsUrl) {
|
||||
return [];
|
||||
}
|
||||
try {
|
||||
const context = await this.requestService.request({ type: 'GET', url: this.productService.extensionsGallery?.recommendationsUrl }, CancellationToken.None);
|
||||
if (context.res.statusCode !== 200) {
|
||||
return [];
|
||||
}
|
||||
const result = await asJson<{ workspaceRecommendations?: IWorkspaceTips[] }>(context);
|
||||
if (!result) {
|
||||
return [];
|
||||
}
|
||||
return result.workspaceRecommendations || [];
|
||||
} catch (error) {
|
||||
this.logService.error(error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { getDomainsOfRemotes, getRemotes } from 'vs/platform/extensionManagement/common/configRemotes';
|
||||
|
||||
suite('Config Remotes', () => {
|
||||
|
||||
const whitelist = [
|
||||
'github.com',
|
||||
'github2.com',
|
||||
'github3.com',
|
||||
'example.com',
|
||||
'example2.com',
|
||||
'example3.com',
|
||||
'server.org',
|
||||
'server2.org',
|
||||
];
|
||||
|
||||
test('HTTPS remotes', function () {
|
||||
assert.deepStrictEqual(getDomainsOfRemotes(remote('https://github.com/Microsoft/vscode.git'), whitelist), ['github.com']);
|
||||
assert.deepStrictEqual(getDomainsOfRemotes(remote('https://git.example.com/gitproject.git'), whitelist), ['example.com']);
|
||||
assert.deepStrictEqual(getDomainsOfRemotes(remote('https://username@github2.com/username/repository.git'), whitelist), ['github2.com']);
|
||||
assert.deepStrictEqual(getDomainsOfRemotes(remote('https://username:password@github3.com/username/repository.git'), whitelist), ['github3.com']);
|
||||
assert.deepStrictEqual(getDomainsOfRemotes(remote('https://username:password@example2.com:1234/username/repository.git'), whitelist), ['example2.com']);
|
||||
assert.deepStrictEqual(getDomainsOfRemotes(remote('https://example3.com:1234/username/repository.git'), whitelist), ['example3.com']);
|
||||
});
|
||||
|
||||
test('SSH remotes', function () {
|
||||
assert.deepStrictEqual(getDomainsOfRemotes(remote('ssh://user@git.server.org/project.git'), whitelist), ['server.org']);
|
||||
});
|
||||
|
||||
test('SCP-like remotes', function () {
|
||||
assert.deepStrictEqual(getDomainsOfRemotes(remote('git@github.com:Microsoft/vscode.git'), whitelist), ['github.com']);
|
||||
assert.deepStrictEqual(getDomainsOfRemotes(remote('user@git.server.org:project.git'), whitelist), ['server.org']);
|
||||
assert.deepStrictEqual(getDomainsOfRemotes(remote('git.server2.org:project.git'), whitelist), ['server2.org']);
|
||||
});
|
||||
|
||||
test('Local remotes', function () {
|
||||
assert.deepStrictEqual(getDomainsOfRemotes(remote('/opt/git/project.git'), whitelist), []);
|
||||
assert.deepStrictEqual(getDomainsOfRemotes(remote('file:///opt/git/project.git'), whitelist), []);
|
||||
});
|
||||
|
||||
test('Multiple remotes', function () {
|
||||
const config = ['https://github.com/Microsoft/vscode.git', 'https://git.example.com/gitproject.git'].map(remote).join('');
|
||||
assert.deepStrictEqual(getDomainsOfRemotes(config, whitelist).sort(), ['example.com', 'github.com']);
|
||||
});
|
||||
|
||||
test('Whitelisting', () => {
|
||||
const config = ['https://github.com/Microsoft/vscode.git', 'https://git.foobar.com/gitproject.git'].map(remote).join('');
|
||||
assert.deepStrictEqual(getDomainsOfRemotes(config, whitelist).sort(), ['aaaaaa.aaa', 'github.com']);
|
||||
});
|
||||
|
||||
test('HTTPS remotes to be hashed', function () {
|
||||
assert.deepStrictEqual(getRemotes(remote('https://github.com/Microsoft/vscode.git')), ['github.com/Microsoft/vscode.git']);
|
||||
assert.deepStrictEqual(getRemotes(remote('https://git.example.com/gitproject.git')), ['git.example.com/gitproject.git']);
|
||||
assert.deepStrictEqual(getRemotes(remote('https://username@github2.com/username/repository.git')), ['github2.com/username/repository.git']);
|
||||
assert.deepStrictEqual(getRemotes(remote('https://username:password@github3.com/username/repository.git')), ['github3.com/username/repository.git']);
|
||||
assert.deepStrictEqual(getRemotes(remote('https://username:password@example2.com:1234/username/repository.git')), ['example2.com/username/repository.git']);
|
||||
assert.deepStrictEqual(getRemotes(remote('https://example3.com:1234/username/repository.git')), ['example3.com/username/repository.git']);
|
||||
|
||||
// Strip .git
|
||||
assert.deepStrictEqual(getRemotes(remote('https://github.com/Microsoft/vscode.git'), true), ['github.com/Microsoft/vscode']);
|
||||
assert.deepStrictEqual(getRemotes(remote('https://git.example.com/gitproject.git'), true), ['git.example.com/gitproject']);
|
||||
assert.deepStrictEqual(getRemotes(remote('https://username@github2.com/username/repository.git'), true), ['github2.com/username/repository']);
|
||||
assert.deepStrictEqual(getRemotes(remote('https://username:password@github3.com/username/repository.git'), true), ['github3.com/username/repository']);
|
||||
assert.deepStrictEqual(getRemotes(remote('https://username:password@example2.com:1234/username/repository.git'), true), ['example2.com/username/repository']);
|
||||
assert.deepStrictEqual(getRemotes(remote('https://example3.com:1234/username/repository.git'), true), ['example3.com/username/repository']);
|
||||
|
||||
// Compare Striped .git with no .git
|
||||
assert.deepStrictEqual(getRemotes(remote('https://github.com/Microsoft/vscode.git'), true), getRemotes(remote('https://github.com/Microsoft/vscode')));
|
||||
assert.deepStrictEqual(getRemotes(remote('https://git.example.com/gitproject.git'), true), getRemotes(remote('https://git.example.com/gitproject')));
|
||||
assert.deepStrictEqual(getRemotes(remote('https://username@github2.com/username/repository.git'), true), getRemotes(remote('https://username@github2.com/username/repository')));
|
||||
assert.deepStrictEqual(getRemotes(remote('https://username:password@github3.com/username/repository.git'), true), getRemotes(remote('https://username:password@github3.com/username/repository')));
|
||||
assert.deepStrictEqual(getRemotes(remote('https://username:password@example2.com:1234/username/repository.git'), true), getRemotes(remote('https://username:password@example2.com:1234/username/repository')));
|
||||
assert.deepStrictEqual(getRemotes(remote('https://example3.com:1234/username/repository.git'), true), getRemotes(remote('https://example3.com:1234/username/repository')));
|
||||
});
|
||||
|
||||
test('SSH remotes to be hashed', function () {
|
||||
assert.deepStrictEqual(getRemotes(remote('ssh://user@git.server.org/project.git')), ['git.server.org/project.git']);
|
||||
|
||||
// Strip .git
|
||||
assert.deepStrictEqual(getRemotes(remote('ssh://user@git.server.org/project.git'), true), ['git.server.org/project']);
|
||||
|
||||
// Compare Striped .git with no .git
|
||||
assert.deepStrictEqual(getRemotes(remote('ssh://user@git.server.org/project.git'), true), getRemotes(remote('ssh://user@git.server.org/project')));
|
||||
});
|
||||
|
||||
test('SCP-like remotes to be hashed', function () {
|
||||
assert.deepStrictEqual(getRemotes(remote('git@github.com:Microsoft/vscode.git')), ['github.com/Microsoft/vscode.git']);
|
||||
assert.deepStrictEqual(getRemotes(remote('user@git.server.org:project.git')), ['git.server.org/project.git']);
|
||||
assert.deepStrictEqual(getRemotes(remote('git.server2.org:project.git')), ['git.server2.org/project.git']);
|
||||
|
||||
// Strip .git
|
||||
assert.deepStrictEqual(getRemotes(remote('git@github.com:Microsoft/vscode.git'), true), ['github.com/Microsoft/vscode']);
|
||||
assert.deepStrictEqual(getRemotes(remote('user@git.server.org:project.git'), true), ['git.server.org/project']);
|
||||
assert.deepStrictEqual(getRemotes(remote('git.server2.org:project.git'), true), ['git.server2.org/project']);
|
||||
|
||||
// Compare Striped .git with no .git
|
||||
assert.deepStrictEqual(getRemotes(remote('git@github.com:Microsoft/vscode.git'), true), getRemotes(remote('git@github.com:Microsoft/vscode')));
|
||||
assert.deepStrictEqual(getRemotes(remote('user@git.server.org:project.git'), true), getRemotes(remote('user@git.server.org:project')));
|
||||
assert.deepStrictEqual(getRemotes(remote('git.server2.org:project.git'), true), getRemotes(remote('git.server2.org:project')));
|
||||
});
|
||||
|
||||
test('Local remotes to be hashed', function () {
|
||||
assert.deepStrictEqual(getRemotes(remote('/opt/git/project.git')), []);
|
||||
assert.deepStrictEqual(getRemotes(remote('file:///opt/git/project.git')), []);
|
||||
});
|
||||
|
||||
test('Multiple remotes to be hashed', function () {
|
||||
const config = ['https://github.com/Microsoft/vscode.git', 'https://git.example.com/gitproject.git'].map(remote).join(' ');
|
||||
assert.deepStrictEqual(getRemotes(config), ['github.com/Microsoft/vscode.git', 'git.example.com/gitproject.git']);
|
||||
|
||||
// Strip .git
|
||||
assert.deepStrictEqual(getRemotes(config, true), ['github.com/Microsoft/vscode', 'git.example.com/gitproject']);
|
||||
|
||||
// Compare Striped .git with no .git
|
||||
const noDotGitConfig = ['https://github.com/Microsoft/vscode', 'https://git.example.com/gitproject'].map(remote).join(' ');
|
||||
assert.deepStrictEqual(getRemotes(config, true), getRemotes(noDotGitConfig));
|
||||
});
|
||||
|
||||
function remote(url: string): string {
|
||||
return `[remote "origin"]
|
||||
url = ${url}
|
||||
fetch = +refs/heads/*:refs/remotes/origin/*
|
||||
`;
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user