Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
一杯枸杞茶ya
csdn-workflow
提交
8406e3a8
C
csdn-workflow
项目概览
一杯枸杞茶ya
/
csdn-workflow
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
Star
0
Fork
1
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
C
csdn-workflow
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
8406e3a8
编写于
5月 11, 2021
作者:
T
Tomas Vik
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
refactor: expose GitService and GitLab service in WrappedRepository
上级
0a7b9524
变更
15
隐藏空白更改
内联
并排
Showing
15 changed file
with
216 addition
and
196 deletion
+216
-196
src/commands/insert_snippet.ts
src/commands/insert_snippet.ts
+5
-6
src/git/git_extension_wrapper.test.ts
src/git/git_extension_wrapper.test.ts
+11
-2
src/git/git_extension_wrapper.ts
src/git/git_extension_wrapper.ts
+6
-0
src/git/wrapped_repository.test.ts
src/git/wrapped_repository.test.ts
+80
-0
src/git/wrapped_repository.ts
src/git/wrapped_repository.ts
+73
-0
src/git_service.test.ts
src/git_service.test.ts
+4
-3
src/gitlab_service.ts
src/gitlab_service.ts
+3
-3
src/openers.ts
src/openers.ts
+4
-6
src/test_utils/fake_git_extension.ts
src/test_utils/fake_git_extension.ts
+19
-2
src/utils/get_extension_configuration.ts
src/utils/get_extension_configuration.ts
+2
-0
src/utils/get_instance_url.test.ts
src/utils/get_instance_url.test.ts
+0
-83
src/utils/get_instance_url.ts
src/utils/get_instance_url.ts
+5
-88
test/integration/mr_review.test.js
test/integration/mr_review.test.js
+1
-1
test/integration/user_agent.test.js
test/integration/user_agent.test.js
+2
-1
test/integration/webview.test.js
test/integration/webview.test.js
+1
-1
未找到文件。
src/commands/insert_snippet.ts
浏览文件 @
8406e3a8
import
*
as
vscode
from
'
vscode
'
;
import
{
gitExtensionWrapper
}
from
'
../git/git_extension_wrapper
'
;
import
{
GqlBlob
,
GqlSnippet
}
from
'
../gitlab/graphql/get_snippets
'
;
import
{
createGitService
,
createGitLabNewService
}
from
'
../service_factory
'
;
const
pickSnippet
=
async
(
snippets
:
GqlSnippet
[])
=>
{
const
quickPickItems
=
snippets
.
map
(
s
=>
({
...
...
@@ -31,10 +30,10 @@ export const insertSnippet = async (): Promise<void> => {
if
(
!
repository
)
{
return
;
}
const
gitService
=
createGitService
(
repository
.
rootFsPath
);
const
gitLabService
=
await
createGitLabNewService
(
repository
.
rootFsPath
);
const
remote
=
await
gitService
.
fetchGitRemote
();
const
snippets
=
await
gitLabService
.
getSnippets
(
`
${
remote
.
namespace
}
/
${
remote
.
project
}
`
);
const
remote
=
await
repository
.
gitService
.
fetchGitRemote
(
);
const
snippets
=
await
repository
.
gitLabService
.
getSnippets
(
`
${
remote
.
namespace
}
/
${
remote
.
project
}
`
,
);
if
(
snippets
.
length
===
0
)
{
vscode
.
window
.
showInformationMessage
(
'
There are no project snippets.
'
);
return
;
...
...
@@ -49,7 +48,7 @@ export const insertSnippet = async (): Promise<void> => {
if
(
!
blob
)
{
return
;
}
const
snippet
=
await
gitLabService
.
getSnippetContent
(
result
.
original
,
blob
);
const
snippet
=
await
repository
.
gitLabService
.
getSnippetContent
(
result
.
original
,
blob
);
const
editor
=
vscode
.
window
.
activeTextEditor
;
await
editor
.
edit
(
editBuilder
=>
{
editBuilder
.
insert
(
editor
.
selection
.
start
,
snippet
);
...
...
src/git/git_extension_wrapper.test.ts
浏览文件 @
8406e3a8
...
...
@@ -33,8 +33,8 @@ describe('GitExtensionWrapper', () => {
});
describe
(
'
repositories
'
,
()
=>
{
const
fakeRepository
=
createFakeRepository
(
'
/repository/root/path/
'
);
const
fakeRepository2
=
createFakeRepository
(
'
/repository/root/path2/
'
);
const
fakeRepository
=
createFakeRepository
(
{
rootUriPath
:
'
/repository/root/path/
'
}
);
const
fakeRepository2
=
createFakeRepository
(
{
rootUriPath
:
'
/repository/root/path2/
'
}
);
it
(
'
returns no repositories when the extension is disabled
'
,
()
=>
{
fakeExtension
.
gitApi
.
repositories
=
[
fakeRepository
];
...
...
@@ -104,5 +104,14 @@ describe('GitExtensionWrapper', () => {
fakeRepository2
.
rootUri
.
fsPath
,
]);
});
it
(
'
returns repository wrapped repository for a repositoryRootPath
'
,
()
=>
{
fakeExtension
.
gitApi
.
repositories
=
[
fakeRepository
,
fakeRepository2
];
wrapper
.
init
();
const
repository
=
wrapper
.
getRepository
(
'
/repository/root/path/
'
);
expect
(
repository
?.
rootFsPath
).
toBe
(
'
/repository/root/path/
'
);
});
});
});
src/git/git_extension_wrapper.ts
浏览文件 @
8406e3a8
...
...
@@ -48,6 +48,12 @@ export class GitExtensionWrapper implements vscode.Disposable {
return
this
.
wrappedRepositories
;
}
getRepository
(
repositoryRoot
:
string
):
WrappedRepository
|
undefined
{
const
rawRepository
=
this
.
gitApi
?.
getRepository
(
vscode
.
Uri
.
file
(
repositoryRoot
));
if
(
!
rawRepository
)
return
undefined
;
return
this
.
repositories
.
find
(
r
=>
r
.
hasSameRootAs
(
rawRepository
));
}
private
register
()
{
assert
(
this
.
gitExtension
);
try
{
...
...
src/git/wrapped_repository.test.ts
0 → 100644
浏览文件 @
8406e3a8
import
*
as
vscode
from
'
vscode
'
;
import
{
WrappedRepository
}
from
'
./wrapped_repository
'
;
import
{
getExtensionConfiguration
}
from
'
../utils/get_extension_configuration
'
;
import
{
tokenService
}
from
'
../services/token_service
'
;
import
{
createFakeRepository
}
from
'
../test_utils/fake_git_extension
'
;
import
{
Repository
}
from
'
../api/git
'
;
import
{
GITLAB_COM_URL
}
from
'
../constants
'
;
jest
.
mock
(
'
../utils/get_extension_configuration
'
);
describe
(
'
WrappedRepository
'
,
()
=>
{
let
repository
:
Repository
;
let
wrappedRepository
:
WrappedRepository
;
beforeEach
(()
=>
{
repository
=
createFakeRepository
();
wrappedRepository
=
new
WrappedRepository
(
repository
);
});
describe
(
'
instanceUrl
'
,
()
=>
{
let
tokens
=
{};
const
fakeContext
=
{
globalState
:
{
get
:
()
=>
tokens
,
},
};
beforeEach
(()
=>
{
tokens
=
{};
tokenService
.
init
((
fakeContext
as
any
)
as
vscode
.
ExtensionContext
);
});
it
(
'
should return configured instanceUrl
'
,
async
()
=>
{
(
getExtensionConfiguration
as
jest
.
Mock
).
mockReturnValue
({
instanceUrl
:
'
https://test.com
'
,
});
expect
(
wrappedRepository
.
instanceUrl
).
toBe
(
'
https://test.com
'
);
});
it
(
'
returns default instanceUrl when there is no configuration
'
,
async
()
=>
{
(
getExtensionConfiguration
as
jest
.
Mock
).
mockReturnValue
({});
expect
(
wrappedRepository
.
instanceUrl
).
toBe
(
GITLAB_COM_URL
);
});
describe
(
'
heuristic
'
,
()
=>
{
it
(
'
returns instanceUrl when there is exactly one match between remotes and token URLs
'
,
async
()
=>
{
repository
=
createFakeRepository
({
remotes
:
[
'
https://git@gitlab.com/gitlab-org/gitlab-vscode-extension.git
'
,
'
https://git@test-instance.com/g/extension.git
'
,
],
});
tokens
=
{
'
https://test-instance.com
'
:
'
abc
'
,
};
wrappedRepository
=
new
WrappedRepository
(
repository
);
expect
(
wrappedRepository
.
instanceUrl
).
toBe
(
'
https://test-instance.com
'
);
});
it
(
'
returns default instanceUrl when there is multiple matches between remotes and token URLs
'
,
async
()
=>
{
repository
=
createFakeRepository
({
remotes
:
[
'
https://git@gitlab.com/gitlab-org/gitlab-vscode-extension.git
'
,
'
https://git@test-instance.com/g/extension.git
'
,
],
});
tokens
=
{
'
https://test-instance.com
'
:
'
abc
'
,
'
https://gitlab.com
'
:
'
def
'
,
};
wrappedRepository
=
new
WrappedRepository
(
repository
);
expect
(
wrappedRepository
.
instanceUrl
).
toBe
(
GITLAB_COM_URL
);
});
});
});
});
src/git/wrapped_repository.ts
浏览文件 @
8406e3a8
import
*
as
url
from
'
url
'
;
import
{
basename
}
from
'
path
'
;
import
{
Repository
}
from
'
../api/git
'
;
import
{
GITLAB_COM_URL
}
from
'
../constants
'
;
import
{
tokenService
}
from
'
../services/token_service
'
;
import
{
log
}
from
'
../log
'
;
import
{
parseGitRemote
}
from
'
./git_remote_parser
'
;
import
{
getExtensionConfiguration
}
from
'
../utils/get_extension_configuration
'
;
import
{
GitLabNewService
}
from
'
../gitlab/gitlab_new_service
'
;
import
{
GitService
}
from
'
../git_service
'
;
function
intersectionOfInstanceAndTokenUrls
(
gitRemoteHosts
:
string
[])
{
const
instanceUrls
=
tokenService
.
getInstanceUrls
();
return
instanceUrls
.
filter
(
instanceUrl
=>
gitRemoteHosts
.
includes
(
url
.
parse
(
instanceUrl
).
host
||
''
),
);
}
function
heuristicInstanceUrl
(
gitRemoteHosts
:
string
[])
{
// if the intersection of git remotes and configured PATs exists and is exactly
// one hostname, use it
const
intersection
=
intersectionOfInstanceAndTokenUrls
(
gitRemoteHosts
);
if
(
intersection
.
length
===
1
)
{
const
heuristicUrl
=
intersection
[
0
];
log
(
`Found
${
heuristicUrl
}
in the PAT list and git remotes, using it as the instanceUrl`
);
return
heuristicUrl
;
}
if
(
intersection
.
length
>
1
)
{
log
(
`Found more than one intersection of git remotes and configured PATs,
${
intersection
}
`
);
}
return
null
;
}
export
function
getInstanceUrlFromRemotes
(
gitRemoteUrls
:
string
[]):
string
{
const
{
instanceUrl
}
=
getExtensionConfiguration
();
// if the workspace setting exists, use it
if
(
instanceUrl
)
{
return
instanceUrl
;
}
// try to determine the instance URL heuristically
const
gitRemoteHosts
=
gitRemoteUrls
.
map
((
uri
:
string
)
=>
parseGitRemote
(
uri
)?.
host
)
.
filter
((
h
):
h
is
string
=>
Boolean
(
h
));
const
heuristicUrl
=
heuristicInstanceUrl
(
gitRemoteHosts
);
if
(
heuristicUrl
)
{
return
heuristicUrl
;
}
// default to Gitlab cloud
return
GITLAB_COM_URL
;
}
export
class
WrappedRepository
{
private
readonly
rawRepository
:
Repository
;
...
...
@@ -8,6 +62,25 @@ export class WrappedRepository {
this
.
rawRepository
=
rawRepository
;
}
get
instanceUrl
():
string
{
const
remoteUrls
=
this
.
rawRepository
.
state
.
remotes
.
map
(
r
=>
r
.
fetchUrl
)
.
filter
((
r
):
r
is
string
=>
Boolean
(
r
));
return
getInstanceUrlFromRemotes
(
remoteUrls
);
}
get
gitLabService
():
GitLabNewService
{
return
new
GitLabNewService
(
this
.
instanceUrl
);
}
get
gitService
():
GitService
{
const
{
remoteName
}
=
getExtensionConfiguration
();
return
new
GitService
({
repositoryRoot
:
this
.
rootFsPath
,
preferredRemoteName
:
remoteName
,
});
}
get
name
():
string
{
return
basename
(
this
.
rawRepository
.
rootUri
.
fsPath
);
}
...
...
src/git_service.test.ts
浏览文件 @
8406e3a8
...
...
@@ -5,6 +5,9 @@ import * as path from 'path';
import
simpleGit
,
{
SimpleGit
}
from
'
simple-git
'
;
import
{
GitService
,
GitServiceOptions
}
from
'
./git_service
'
;
import
{
gitExtensionWrapper
}
from
'
./git/git_extension_wrapper
'
;
import
{
getInstanceUrl
}
from
'
./utils/get_instance_url
'
;
jest
.
mock
(
'
./utils/get_instance_url
'
);
const
isMac
=
()
=>
Boolean
(
process
.
platform
.
match
(
/darwin/
));
...
...
@@ -37,9 +40,7 @@ describe('git_service', () => {
});
beforeEach
(()
=>
{
(
vscode
.
workspace
.
getConfiguration
as
jest
.
Mock
).
mockReturnValue
({
instanceUrl
:
'
https://gitlab.com
'
,
});
(
getInstanceUrl
as
jest
.
Mock
).
mockReturnValue
(
'
https://gitlab.com
'
);
jest
.
spyOn
(
gitExtensionWrapper
,
'
gitBinaryPath
'
,
'
get
'
).
mockReturnValue
(
'
git
'
);
});
...
...
src/gitlab_service.ts
浏览文件 @
8406e3a8
...
...
@@ -40,7 +40,7 @@ const projectCache: Record<string, GitLabProject> = {};
let
versionCache
:
string
|
null
=
null
;
async
function
fetch
(
repositoryRoot
:
string
|
undefined
,
repositoryRoot
:
string
,
path
:
string
,
method
=
'
GET
'
,
data
?:
Record
<
string
,
unknown
>
,
...
...
@@ -161,7 +161,7 @@ export async function fetchCurrentUser(repositoryRoot: string): Promise<RestUser
}
}
async
function
fetchFirstUserByUsername
(
repositoryRoot
:
string
|
undefined
,
userName
:
string
)
{
async
function
fetchFirstUserByUsername
(
repositoryRoot
:
string
,
userName
:
string
)
{
try
{
const
{
response
:
users
}
=
await
fetch
(
repositoryRoot
,
`/users?username=
${
userName
}
`
);
return
users
[
0
];
...
...
@@ -360,7 +360,7 @@ export async function fetchIssuables(params: CustomQuery, repositoryRoot: string
const
{
response
}
=
await
fetch
(
repositoryRoot
,
`
${
path
}
?
${
search
.
toString
()}
`
);
issuable
=
response
;
return
issuable
.
map
(
normalizeAvatarUrl
(
await
getInstanceUrl
()));
return
issuable
.
map
(
normalizeAvatarUrl
(
await
getInstanceUrl
(
repositoryRoot
)));
}
export
async
function
fetchLastJobsForCurrentBranch
(
...
...
src/openers.ts
浏览文件 @
8406e3a8
...
...
@@ -2,7 +2,6 @@ import * as path from 'path';
import
*
as
vscode
from
'
vscode
'
;
import
*
as
assert
from
'
assert
'
;
import
*
as
gitLabService
from
'
./gitlab_service
'
;
import
{
createGitService
}
from
'
./service_factory
'
;
import
{
handleError
}
from
'
./log
'
;
import
{
VS_COMMANDS
}
from
'
./command_names
'
;
import
{
gitExtensionWrapper
}
from
'
./git/git_extension_wrapper
'
;
...
...
@@ -68,10 +67,9 @@ async function getActiveFile() {
return
undefined
;
}
const
gitService
=
createGitService
(
repository
.
rootFsPath
);
const
branchName
=
await
gitService
.
fetchTrackingBranchName
();
const
branchName
=
await
repository
.
gitService
.
fetchTrackingBranchName
();
const
filePath
=
path
.
relative
(
await
gitService
.
getRepositoryRootFolder
(),
await
repository
.
gitService
.
getRepositoryRootFolder
(),
editor
.
document
.
uri
.
fsPath
,
);
const
fileUrl
=
`
${
currentProject
!
.
webUrl
}
/blob/
${
branchName
}
/
${
filePath
}
`
;
...
...
@@ -120,7 +118,7 @@ export async function openCreateNewMr(): Promise<void> {
const
repository
=
await
gitExtensionWrapper
.
getActiveRepositoryOrSelectOne
();
if
(
!
repository
)
return
;
const
project
=
await
gitLabService
.
fetchCurrentProject
(
repository
.
rootFsPath
);
const
branchName
=
await
createGitService
(
repository
.
rootFsPath
)
.
fetchTrackingBranchName
();
const
branchName
=
await
repository
.
gitService
.
fetchTrackingBranchName
();
openUrl
(
`
${
project
!
.
webUrl
}
/merge_requests/new?merge_request%5Bsource_branch%5D=
${
branchName
}
`
);
}
...
...
@@ -142,7 +140,7 @@ export async function compareCurrentBranch(): Promise<void> {
if
(
!
repository
)
return
;
const
project
=
await
gitLabService
.
fetchCurrentProject
(
repository
.
rootFsPath
);
const
lastCommitId
=
await
createGitService
(
repository
.
rootFsPath
)
.
fetchLastCommitId
();
const
lastCommitId
=
await
repository
.
gitService
.
fetchLastCommitId
();
if
(
project
&&
lastCommitId
)
{
openUrl
(
`
${
project
.
webUrl
}
/compare/master...
${
lastCommitId
}
`
);
...
...
src/test_utils/fake_git_extension.ts
浏览文件 @
8406e3a8
...
...
@@ -7,8 +7,21 @@ const removeFromArray = (array: any[], element: any): any[] => {
return
array
.
filter
(
el
=>
el
!==
element
);
};
export
const
createFakeRepository
=
(
rootUriPath
:
string
):
Repository
=>
(({
rootUri
:
vscode
.
Uri
.
file
(
rootUriPath
)
}
as
unknown
)
as
Repository
);
export
const
fakeStateOptions
=
{
rootUriPath
:
'
/path/to/repo
'
,
remotes
:
[
'
git@a.com:gitlab/extension.git
'
,
'
git@b.com:gitlab/extension.git
'
],
};
export
const
createFakeRepository
=
(
options
:
Partial
<
typeof
fakeStateOptions
>
=
{},
):
Repository
=>
{
const
{
rootUriPath
,
remotes
}
=
{
...
fakeStateOptions
,
...
options
};
return
({
rootUri
:
vscode
.
Uri
.
file
(
rootUriPath
),
state
:
{
remotes
:
remotes
.
map
(
r
=>
({
fetchUrl
:
r
})),
},
}
as
unknown
)
as
Repository
;
};
/**
* This is a simple test double for the native Git extension API
...
...
@@ -40,6 +53,10 @@ class FakeGitApi {
};
}
getRepository
(
uri
:
vscode
.
Uri
)
{
return
this
.
repositories
.
find
(
r
=>
r
.
rootUri
.
toString
()
===
uri
.
toString
());
}
registerRemoteSourceProvider
(
provider
:
any
)
{
this
.
remoteSourceProviders
.
push
(
provider
);
return
{
...
...
src/utils/get_extension_configuration.ts
浏览文件 @
8406e3a8
...
...
@@ -2,6 +2,7 @@ import * as vscode from 'vscode';
import
{
CONFIG_NAMESPACE
}
from
'
../constants
'
;
interface
ExtensionConfiguration
{
instanceUrl
?:
string
;
remoteName
?:
string
;
pipelineGitRemoteName
?:
string
;
featureFlags
?:
string
[];
...
...
@@ -13,6 +14,7 @@ const turnNullToUndefined = <T>(val: T | null | undefined): T | undefined => val
export
function
getExtensionConfiguration
():
ExtensionConfiguration
{
const
workspaceConfig
=
vscode
.
workspace
.
getConfiguration
(
CONFIG_NAMESPACE
);
return
{
instanceUrl
:
turnNullToUndefined
(
workspaceConfig
.
instanceUrl
),
remoteName
:
turnNullToUndefined
(
workspaceConfig
.
remoteName
),
pipelineGitRemoteName
:
turnNullToUndefined
(
workspaceConfig
.
pipelineGitRemoteName
),
featureFlags
:
turnNullToUndefined
(
workspaceConfig
.
featureFlags
),
...
...
src/utils/get_instance_url.test.ts
已删除
100644 → 0
浏览文件 @
0a7b9524
import
*
as
temp
from
'
temp
'
;
import
*
as
vscode
from
'
vscode
'
;
import
simpleGit
,
{
SimpleGit
}
from
'
simple-git
'
;
import
{
getInstanceUrl
}
from
'
./get_instance_url
'
;
import
{
tokenService
}
from
'
../services/token_service
'
;
import
{
GITLAB_COM_URL
}
from
'
../constants
'
;
import
{
gitExtensionWrapper
}
from
'
../git/git_extension_wrapper
'
;
describe
(
'
get_instance_url
'
,
()
=>
{
const
ORIGIN
=
'
origin
'
;
const
SECOND_REMOTE
=
'
second
'
;
// name is important, we need this remote to be alphabetically behind origin
let
repositoryRoot
:
string
;
let
git
:
SimpleGit
;
temp
.
track
();
// clean temporary folders after the tests finish
const
createTempFolder
=
():
Promise
<
string
>
=>
new
Promise
((
resolve
,
reject
)
=>
{
temp
.
mkdir
(
'
vscodeWorkplace
'
,
(
err
,
dirPath
)
=>
{
if
(
err
)
reject
(
err
);
resolve
(
dirPath
);
});
});
beforeEach
(()
=>
{
jest
.
spyOn
(
gitExtensionWrapper
,
'
gitBinaryPath
'
,
'
get
'
).
mockReturnValue
(
'
git
'
);
});
it
(
'
returns configured instanceUrl if the config contains one
'
,
async
()
=>
{
(
vscode
.
workspace
.
getConfiguration
as
jest
.
Mock
).
mockReturnValue
({
instanceUrl
:
'
https://test.com
'
,
});
expect
(
await
getInstanceUrl
()).
toBe
(
'
https://test.com
'
);
});
it
(
'
returns default instanceUrl when there is no configuration
'
,
async
()
=>
{
(
vscode
.
workspace
.
getConfiguration
as
jest
.
Mock
).
mockReturnValue
({});
expect
(
await
getInstanceUrl
()).
toBe
(
GITLAB_COM_URL
);
});
describe
(
'
heuristic
'
,
()
=>
{
let
tokens
=
{};
const
fakeContext
=
{
globalState
:
{
get
:
()
=>
tokens
,
},
};
beforeEach
(
async
()
=>
{
repositoryRoot
=
await
createTempFolder
();
git
=
simpleGit
(
repositoryRoot
,
{
binary
:
'
git
'
});
await
git
.
init
();
await
git
.
addRemote
(
ORIGIN
,
'
https://git@gitlab.com/gitlab-org/gitlab-vscode-extension.git
'
);
tokens
=
{};
tokenService
.
init
((
fakeContext
as
any
)
as
vscode
.
ExtensionContext
);
});
it
(
'
returns instanceUrl when there is exactly one match between remotes and token URLs
'
,
async
()
=>
{
await
git
.
addRemote
(
SECOND_REMOTE
,
'
https://git@test-instance.com/g/extension.git
'
);
tokens
=
{
'
https://test-instance.com
'
:
'
abc
'
,
};
expect
(
await
getInstanceUrl
(
repositoryRoot
)).
toBe
(
'
https://test-instance.com
'
);
});
it
(
'
returns default instanceUrl when there is multiple matches between remotes and token URLs
'
,
async
()
=>
{
await
git
.
addRemote
(
SECOND_REMOTE
,
'
https://git@test-instance.com/g/extension.git
'
);
tokens
=
{
'
https://test-instance.com
'
:
'
abc
'
,
'
https://gitlab.com
'
:
'
def
'
,
};
expect
(
await
getInstanceUrl
(
repositoryRoot
)).
toBe
(
GITLAB_COM_URL
);
});
it
(
'
it works with URLs in git format
'
,
async
()
=>
{
await
git
.
addRemote
(
SECOND_REMOTE
,
'
git@test-instance.com:g/extension.git
'
);
tokens
=
{
'
https://test-instance.com
'
:
'
abc
'
,
};
expect
(
await
getInstanceUrl
(
repositoryRoot
)).
toBe
(
'
https://test-instance.com
'
);
});
});
});
src/utils/get_instance_url.ts
浏览文件 @
8406e3a8
import
*
as
vscode
from
'
vscode
'
;
import
*
as
execa
from
'
execa
'
;
import
*
as
url
from
'
url
'
;
import
{
GITLAB_COM_URL
}
from
'
../constants
'
;
import
{
tokenService
}
from
'
../services/token_service
'
;
import
{
log
}
from
'
../log
'
;
import
{
parseGitRemote
}
from
'
../git/git_remote_parser
'
;
import
*
as
assert
from
'
assert
'
;
import
{
gitExtensionWrapper
}
from
'
../git/git_extension_wrapper
'
;
async
function
fetch
(
cmd
:
string
,
repositoryRoot
:
string
):
Promise
<
string
|
null
>
{
const
[,
...
args
]
=
cmd
.
trim
().
split
(
'
'
);
const
{
stdout
}
=
await
execa
(
gitExtensionWrapper
.
gitBinaryPath
,
args
,
{
cwd
:
repositoryRoot
,
preferLocal
:
false
,
});
return
stdout
;
}
async
function
fetchGitRemoteUrls
(
repositoryRoot
:
string
):
Promise
<
string
[]
>
{
const
fetchGitRemotesVerbose
=
async
():
Promise
<
string
[]
>
=>
{
const
output
=
await
fetch
(
'
git remote -v
'
,
repositoryRoot
);
return
(
output
||
''
).
split
(
'
\n
'
);
};
const
parseRemoteFromVerboseLine
=
(
line
:
string
)
=>
{
// 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
)).
filter
(
Boolean
);
// git remote -v returns a (fetch) and a (push) line for each remote,
// so we need to remove duplicates
return
[...
new
Set
(
remoteUrls
)];
}
async
function
intersectionOfInstanceAndTokenUrls
(
repositoryRoot
:
string
)
{
const
uriHostname
=
(
uri
:
string
)
=>
parseGitRemote
(
uri
)?.
host
;
const
instanceUrls
=
tokenService
.
getInstanceUrls
();
const
gitRemotes
=
await
fetchGitRemoteUrls
(
repositoryRoot
);
const
gitRemoteHosts
=
gitRemotes
.
map
(
uriHostname
);
return
instanceUrls
.
filter
(
instanceUrl
=>
gitRemoteHosts
.
includes
(
url
.
parse
(
instanceUrl
).
host
||
undefined
),
);
}
async
function
heuristicInstanceUrl
(
repositoryRoot
:
string
)
{
// if the intersection of git remotes and configured PATs exists and is exactly
// one hostname, use it
const
intersection
=
await
intersectionOfInstanceAndTokenUrls
(
repositoryRoot
);
if
(
intersection
.
length
===
1
)
{
const
heuristicUrl
=
intersection
[
0
];
log
(
`Found
${
heuristicUrl
}
in the PAT list and git remotes, using it as the instanceUrl`
);
return
heuristicUrl
;
}
if
(
intersection
.
length
>
1
)
{
log
(
`Found more than one intersection of git remotes and configured PATs,
${
intersection
}
`
);
}
return
null
;
}
export
async
function
getInstanceUrl
(
repositoryRoot
?:
string
):
Promise
<
string
>
{
// FIXME: if you are touching this configuration statement, move the configuration to get_extension_configuration.ts
const
{
instanceUrl
}
=
vscode
.
workspace
.
getConfiguration
(
'
gitlab
'
);
// if the workspace setting exists, use it
if
(
instanceUrl
)
{
return
instanceUrl
;
}
// legacy logic in GitLabService might not have the workspace folder available
// in that case we just skip the heuristic
if
(
repositoryRoot
)
{
// try to determine the instance URL heuristically
const
heuristicUrl
=
await
heuristicInstanceUrl
(
repositoryRoot
);
if
(
heuristicUrl
)
{
return
heuristicUrl
;
}
}
// default to Gitlab cloud
return
GITLAB_COM_URL
;
export
function
getInstanceUrl
(
repositoryRoot
:
string
):
string
{
const
repository
=
gitExtensionWrapper
.
getRepository
(
repositoryRoot
);
assert
(
repository
,
`
${
repositoryRoot
}
doesn't contain a git repository`
);
return
repository
.
instanceUrl
;
}
test/integration/mr_review.test.js
浏览文件 @
8406e3a8
...
...
@@ -57,7 +57,7 @@ describe('MR Review', () => {
beforeEach
(()
=>
{
server
.
resetHandlers
();
dataProvider
=
new
IssuableDataProvider
();
mrItemModel
=
new
MrItemModel
(
openMergeRequestResponse
,
getRepositoryRoot
()
);
mrItemModel
=
new
MrItemModel
(
openMergeRequestResponse
,
{
uri
:
getRepositoryRoot
()
}
);
});
after
(
async
()
=>
{
...
...
test/integration/user_agent.test.js
浏览文件 @
8406e3a8
...
...
@@ -8,6 +8,7 @@ const gitLabService = require('../../src/gitlab_service');
const
{
GitLabNewService
}
=
require
(
'
../../src/gitlab/gitlab_new_service
'
);
const
snippetsResponse
=
require
(
'
./fixtures/graphql/snippets.json
'
);
const
packageJson
=
require
(
'
../../package.json
'
);
const
{
getRepositoryRoot
}
=
require
(
'
./test_infrastructure/helpers
'
);
const
validateUserAgent
=
req
=>
{
const
userAgent
=
req
.
headers
.
get
(
'
User-Agent
'
);
...
...
@@ -50,7 +51,7 @@ describe('User-Agent header', () => {
});
it
(
'
is sent with requests from GitLabService
'
,
async
()
=>
{
await
gitLabService
.
fetchCurrentUser
();
await
gitLabService
.
fetchCurrentUser
(
getRepositoryRoot
()
);
validateUserAgent
(
capturedRequest
);
});
...
...
test/integration/webview.test.js
浏览文件 @
8406e3a8
...
...
@@ -80,7 +80,7 @@ describe('GitLab webview', () => {
replacePanelEventSystem
();
webviewPanel
=
await
webviewController
.
create
(
openIssueResponse
,
vscode
.
workspace
.
workspaceFolders
[
0
],
vscode
.
workspace
.
workspaceFolders
[
0
]
.
uri
.
fsPath
,
);
});
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录