Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/git/common/utils.ts
13401 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { equalsIgnoreCase } from '../../../../base/common/strings.js';
7
import { URI } from '../../../../base/common/uri.js';
8
import { GitRemote, GitRepositoryState } from './gitService.js';
9
10
export function hasGitHubRemotes(repositoryState: GitRepositoryState): boolean {
11
const hosts = ['github.com', 'ghe.com'];
12
const remotes = getOrderedRemotes(repositoryState!)
13
.filter(remote => !!remote.fetchUrl)
14
.map(remote => parseRemoteUrl(remote.fetchUrl!));
15
16
for (const remote of remotes) {
17
if (!remote?.host) {
18
continue;
19
}
20
21
if (
22
hosts.some(host => equalsIgnoreCase(remote.host, host)) ||
23
hosts.some(host => remote.host.endsWith(host))
24
) {
25
return true;
26
}
27
}
28
29
return false;
30
}
31
32
function getOrderedRemotes(repositoryState: GitRepositoryState): readonly GitRemote[] {
33
if (repositoryState.remotes.length < 2) {
34
return repositoryState.remotes;
35
}
36
37
const remotes = new Map<string, GitRemote>();
38
39
// If there's an upstream remote, use that
40
const remoteIndex = repositoryState.remotes.findIndex(r => r.name === repositoryState.HEAD?.upstream?.remote);
41
if (remoteIndex !== -1) {
42
const fetchUrl = repositoryState.remotes[remoteIndex].fetchUrl;
43
if (fetchUrl) {
44
remotes.set(repositoryState.remotes[remoteIndex].name, repositoryState.remotes[remoteIndex]);
45
}
46
}
47
48
// If there's a remote named "origin", use that
49
const originIndex = repositoryState.remotes.findIndex(r => r.name === 'origin');
50
if (originIndex !== -1) {
51
const fetchUrl = repositoryState.remotes[originIndex].fetchUrl;
52
if (fetchUrl) {
53
remotes.set(repositoryState.remotes[originIndex].name, repositoryState.remotes[originIndex]);
54
}
55
}
56
57
// Add everything else
58
for (const remote of repositoryState.remotes) {
59
if (!remotes.has(remote.name)) {
60
remotes.set(remote.name, remote);
61
}
62
}
63
64
return Array.from(remotes.values());
65
}
66
67
function parseRemoteUrl(fetchUrl: string): { host: string; rawHost: string; path: string } | undefined {
68
fetchUrl = fetchUrl.trim();
69
try {
70
// Normalize git shorthand syntax ([email protected]:user/repo.git) into an explicit ssh:// url
71
// See https://git-scm.com/docs/git-clone/2.35.0#_git_urls
72
if (/^[\w\d\-]+@/i.test(fetchUrl)) {
73
const parts = fetchUrl.split(':');
74
if (parts.length !== 2) {
75
return undefined;
76
}
77
fetchUrl = 'ssh://' + parts[0] + '/' + parts[1];
78
}
79
80
const repoUrl = URI.parse(fetchUrl);
81
const authority = repoUrl.authority;
82
const path = repoUrl.path;
83
if (!(equalsIgnoreCase(repoUrl.scheme, 'ssh') || equalsIgnoreCase(repoUrl.scheme, 'https') || equalsIgnoreCase(repoUrl.scheme, 'http'))) {
84
return;
85
}
86
87
const splitAuthority = authority.split('@');
88
if (splitAuthority.length > 2) { // Invalid, too many @ symbols
89
return undefined;
90
}
91
92
const extractedHost = splitAuthority.at(-1);
93
if (!extractedHost) {
94
return;
95
}
96
97
const rawHost = extractedHost
98
.toLowerCase()
99
.replace(/:\d+$/, ''); // Remove optional port
100
101
const normalizedHost = rawHost
102
.replace(/^[\w\-]+-/, '') // Remove common ssh syntax: abc-github.com
103
.replace(/-[\w\-]+$/, '');// Remove common ssh syntax: github.com-abc
104
105
return { host: normalizedHost, rawHost, path: path };
106
} catch (err) {
107
return undefined;
108
}
109
}
110
111