Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xxadev
vscode
提交
c7fec928
V
vscode
项目概览
xxadev
/
vscode
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
V
vscode
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
未验证
提交
c7fec928
编写于
4月 27, 2020
作者:
J
João Moreno
提交者:
GitHub
4月 27, 2020
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #96069 from microsoft/joao/github-auth
Provide automatic git authentication to GitHub
上级
ce867918
bce93bef
变更
9
隐藏空白更改
内联
并排
Showing
9 changed file
with
125 addition
and
47 deletion
+125
-47
extensions/git/src/api/api1.ts
extensions/git/src/api/api1.ts
+5
-1
extensions/git/src/api/git.d.ts
extensions/git/src/api/git.d.ts
+11
-0
extensions/git/src/askpass.ts
extensions/git/src/askpass.ts
+56
-20
extensions/git/src/commands.ts
extensions/git/src/commands.ts
+8
-0
extensions/git/src/git.ts
extensions/git/src/git.ts
+1
-1
extensions/git/src/github.ts
extensions/git/src/github.ts
+29
-0
extensions/git/src/ipc/ipcServer.ts
extensions/git/src/ipc/ipcServer.ts
+2
-2
extensions/git/src/main.ts
extensions/git/src/main.ts
+6
-21
extensions/git/src/model.ts
extensions/git/src/model.ts
+7
-2
未找到文件。
extensions/git/src/api/api1.ts
浏览文件 @
c7fec928
...
...
@@ -5,7 +5,7 @@
import
{
Model
}
from
'
../model
'
;
import
{
Repository
as
BaseRepository
,
Resource
}
from
'
../repository
'
;
import
{
InputBox
,
Git
,
API
,
Repository
,
Remote
,
RepositoryState
,
Branch
,
Ref
,
Submodule
,
Commit
,
Change
,
RepositoryUIState
,
Status
,
LogOptions
,
APIState
,
CommitOptions
,
GitExtension
,
RefType
,
RemoteSourceProvider
}
from
'
./git
'
;
import
{
InputBox
,
Git
,
API
,
Repository
,
Remote
,
RepositoryState
,
Branch
,
Ref
,
Submodule
,
Commit
,
Change
,
RepositoryUIState
,
Status
,
LogOptions
,
APIState
,
CommitOptions
,
GitExtension
,
RefType
,
RemoteSourceProvider
,
CredentialsProvider
}
from
'
./git
'
;
import
{
Event
,
SourceControlInputBox
,
Uri
,
SourceControl
,
Disposable
,
commands
}
from
'
vscode
'
;
import
{
mapEvent
}
from
'
../util
'
;
import
{
toGitUri
}
from
'
../uri
'
;
...
...
@@ -263,6 +263,10 @@ export class ApiImpl implements API {
return
this
.
_model
.
registerRemoteSourceProvider
(
provider
);
}
registerCredentialsProvider
(
provider
:
CredentialsProvider
):
Disposable
{
return
this
.
_model
.
registerCredentialsProvider
(
provider
);
}
constructor
(
private
_model
:
Model
)
{
}
}
...
...
extensions/git/src/api/git.d.ts
浏览文件 @
c7fec928
...
...
@@ -204,6 +204,15 @@ export interface RemoteSourceProvider {
getRemoteSources
(
query
?:
string
):
ProviderResult
<
RemoteSource
[]
>
;
}
export
interface
Credentials
{
readonly
username
:
string
;
readonly
password
:
string
;
}
export
interface
CredentialsProvider
{
getCredentials
(
host
:
Uri
):
ProviderResult
<
Credentials
>
;
}
export
type
APIState
=
'
uninitialized
'
|
'
initialized
'
;
export
interface
API
{
...
...
@@ -217,7 +226,9 @@ export interface API {
toGitUri
(
uri
:
Uri
,
ref
:
string
):
Uri
;
getRepository
(
uri
:
Uri
):
Repository
|
null
;
init
(
root
:
Uri
):
Promise
<
Repository
|
null
>
;
registerRemoteSourceProvider
(
provider
:
RemoteSourceProvider
):
Disposable
;
registerCredentialsProvider
(
provider
:
CredentialsProvider
):
Disposable
;
}
export
interface
GitExtension
{
...
...
extensions/git/src/askpass.ts
浏览文件 @
c7fec928
...
...
@@ -3,36 +3,60 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
{
window
,
InputBoxOptions
}
from
'
vscode
'
;
import
{
IDisposable
}
from
'
./util
'
;
import
{
window
,
InputBoxOptions
,
Uri
,
OutputChannel
,
Disposable
}
from
'
vscode
'
;
import
{
IDisposable
,
EmptyDisposable
,
toDisposable
}
from
'
./util
'
;
import
*
as
path
from
'
path
'
;
import
{
IIPCHandler
,
IIPCServer
}
from
'
./ipc/ipcServer
'
;
export
interface
AskpassEnvironment
{
GIT_ASKPASS
:
string
;
ELECTRON_RUN_AS_NODE
?:
string
;
VSCODE_GIT_ASKPASS_NODE
?:
string
;
VSCODE_GIT_ASKPASS_MAIN
?:
string
;
VSCODE_GIT_ASKPASS_HANDLE
?:
string
;
}
import
{
IIPCHandler
,
IIPCServer
,
createIPCServer
}
from
'
./ipc/ipcServer
'
;
import
{
CredentialsProvider
,
Credentials
}
from
'
./api/git
'
;
export
class
Askpass
implements
IIPCHandler
{
private
disposable
:
IDisposable
;
private
disposable
:
IDisposable
=
EmptyDisposable
;
private
cache
=
new
Map
<
string
,
Credentials
>
();
private
credentialsProviders
=
new
Set
<
CredentialsProvider
>
();
static
getDisabledEnv
():
AskpassEnvironment
{
return
{
GIT_ASKPASS
:
path
.
join
(
__dirname
,
'
askpass-empty.sh
'
)
};
static
async
create
(
outputChannel
:
OutputChannel
):
Promise
<
Askpass
>
{
try
{
return
new
Askpass
(
await
createIPCServer
());
}
catch
(
err
)
{
outputChannel
.
appendLine
(
`[error] Failed to create git askpass IPC:
${
err
}
`
);
return
new
Askpass
();
}
}
constructor
(
ipc
:
IIPCServer
)
{
this
.
disposable
=
ipc
.
registerHandler
(
'
askpass
'
,
this
);
private
constructor
(
private
ipc
?:
IIPCServer
)
{
if
(
ipc
)
{
this
.
disposable
=
ipc
.
registerHandler
(
'
askpass
'
,
this
);
}
}
async
handle
({
request
,
host
}:
{
request
:
string
,
host
:
string
}):
Promise
<
string
>
{
const
uri
=
Uri
.
parse
(
host
);
const
authority
=
uri
.
authority
.
replace
(
/^.*@/
,
''
);
const
password
=
/password/i
.
test
(
request
);
const
cached
=
this
.
cache
.
get
(
authority
);
if
(
cached
&&
password
)
{
this
.
cache
.
delete
(
authority
);
return
cached
.
password
;
}
if
(
!
password
)
{
for
(
const
credentialsProvider
of
this
.
credentialsProviders
)
{
try
{
const
credentials
=
await
credentialsProvider
.
getCredentials
(
uri
);
if
(
credentials
)
{
this
.
cache
.
set
(
authority
,
credentials
);
setTimeout
(()
=>
this
.
cache
.
delete
(
authority
),
60
_000
);
return
credentials
.
username
;
}
}
catch
{
}
}
}
const
options
:
InputBoxOptions
=
{
password
:
/password/i
.
test
(
request
)
,
password
,
placeHolder
:
request
,
prompt
:
`Git:
${
host
}
`
,
ignoreFocusOut
:
true
...
...
@@ -41,8 +65,15 @@ export class Askpass implements IIPCHandler {
return
await
window
.
showInputBox
(
options
)
||
''
;
}
getEnv
():
AskpassEnvironment
{
getEnv
():
{
[
key
:
string
]:
string
;
}
{
if
(
!
this
.
ipc
)
{
return
{
GIT_ASKPASS
:
path
.
join
(
__dirname
,
'
askpass-empty.sh
'
)
};
}
return
{
...
this
.
ipc
.
getEnv
(),
ELECTRON_RUN_AS_NODE
:
'
1
'
,
GIT_ASKPASS
:
path
.
join
(
__dirname
,
'
askpass.sh
'
),
VSCODE_GIT_ASKPASS_NODE
:
process
.
execPath
,
...
...
@@ -50,6 +81,11 @@ export class Askpass implements IIPCHandler {
};
}
registerCredentialsProvider
(
provider
:
CredentialsProvider
):
Disposable
{
this
.
credentialsProviders
.
add
(
provider
);
return
toDisposable
(()
=>
this
.
credentialsProviders
.
delete
(
provider
));
}
dispose
():
void
{
this
.
disposable
.
dispose
();
}
...
...
extensions/git/src/commands.ts
浏览文件 @
c7fec928
...
...
@@ -2560,6 +2560,14 @@ export class CommandCenter {
type
=
'
warning
'
;
options
.
modal
=
false
;
break
;
case
GitErrorCodes
.
AuthenticationFailed
:
const
regex
=
/Authentication failed for '
(
.*
)
'/i
;
const
match
=
regex
.
exec
(
err
.
stderr
||
String
(
err
));
message
=
match
?
localize
(
'
auth failed specific
'
,
"
Failed to authenticate to git remote:
\n\n
{0}
"
,
match
[
1
])
:
localize
(
'
auth failed
'
,
"
Failed to authenticate to git remote.
"
);
break
;
case
GitErrorCodes
.
NoUserNameConfigured
:
case
GitErrorCodes
.
NoUserEmailConfigured
:
message
=
localize
(
'
missing user info
'
,
"
Make sure you configure your 'user.name' and 'user.email' in git.
"
);
...
...
extensions/git/src/git.ts
浏览文件 @
c7fec928
...
...
@@ -306,7 +306,7 @@ export interface IGitOptions {
function
getGitErrorCode
(
stderr
:
string
):
string
|
undefined
{
if
(
/Another git process seems to be running in this repository|If no other git process is currently running/
.
test
(
stderr
))
{
return
GitErrorCodes
.
RepositoryIsLocked
;
}
else
if
(
/Authentication failed/
.
test
(
stderr
))
{
}
else
if
(
/Authentication failed/
i
.
test
(
stderr
))
{
return
GitErrorCodes
.
AuthenticationFailed
;
}
else
if
(
/Not a git repository/i
.
test
(
stderr
))
{
return
GitErrorCodes
.
NotAGitRepository
;
...
...
extensions/git/src/github.ts
0 → 100644
浏览文件 @
c7fec928
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
*
as
vscode
from
'
vscode
'
;
import
{
CredentialsProvider
,
Credentials
}
from
'
./api/git
'
;
export
class
GitHubCredentialProvider
implements
CredentialsProvider
{
async
getCredentials
(
host
:
vscode
.
Uri
):
Promise
<
Credentials
|
undefined
>
{
if
(
!
/github
\.
com/i
.
test
(
host
.
authority
))
{
return
;
}
const
session
=
await
this
.
getSession
();
return
{
username
:
session
.
account
.
id
,
password
:
await
session
.
getAccessToken
()
};
}
private
async
getSession
():
Promise
<
vscode
.
AuthenticationSession
>
{
const
authenticationSessions
=
await
vscode
.
authentication
.
getSessions
(
'
github
'
,
[
'
repo
'
]);
if
(
authenticationSessions
.
length
)
{
return
await
authenticationSessions
[
0
];
}
else
{
return
await
vscode
.
authentication
.
login
(
'
github
'
,
[
'
repo
'
]);
}
}
}
extensions/git/src/ipc/ipcServer.ts
浏览文件 @
c7fec928
...
...
@@ -46,7 +46,7 @@ export async function createIPCServer(): Promise<IIPCServer> {
export
interface
IIPCServer
extends
Disposable
{
readonly
ipcHandlePath
:
string
|
undefined
;
getEnv
():
any
;
getEnv
():
{
[
key
:
string
]:
string
;
}
;
registerHandler
(
name
:
string
,
handler
:
IIPCHandler
):
Disposable
;
}
...
...
@@ -91,7 +91,7 @@ class IPCServer implements IIPCServer, Disposable {
});
}
getEnv
():
any
{
getEnv
():
{
[
key
:
string
]:
string
;
}
{
return
{
VSCODE_GIT_IPC_HANDLE
:
this
.
ipcHandlePath
};
}
...
...
extensions/git/src/main.ts
浏览文件 @
c7fec928
...
...
@@ -20,9 +20,9 @@ import { GitProtocolHandler } from './protocolHandler';
import
{
GitExtensionImpl
}
from
'
./api/extension
'
;
import
*
as
path
from
'
path
'
;
import
*
as
fs
from
'
fs
'
;
import
{
createIPCServer
,
IIPCServer
}
from
'
./ipc/ipcServer
'
;
import
{
GitTimelineProvider
}
from
'
./timelineProvider
'
;
import
{
registerAPICommands
}
from
'
./api/api1
'
;
import
{
GitHubCredentialProvider
}
from
'
./github
'
;
const
deactivateTasks
:
{
():
Promise
<
any
>
;
}[]
=
[];
...
...
@@ -36,27 +36,12 @@ async function createModel(context: ExtensionContext, outputChannel: OutputChann
const
pathHint
=
workspace
.
getConfiguration
(
'
git
'
).
get
<
string
>
(
'
path
'
);
const
info
=
await
findGit
(
pathHint
,
path
=>
outputChannel
.
appendLine
(
localize
(
'
looking
'
,
"
Looking for git in: {0}
"
,
path
)));
let
env
:
any
=
{};
let
ipc
:
IIPCServer
|
undefined
;
const
askpass
=
await
Askpass
.
create
(
outputChannel
);
disposables
.
push
(
askpass
);
context
.
subscriptions
.
push
(
askpass
.
registerCredentialsProvider
(
new
GitHubCredentialProvider
()));
try
{
ipc
=
await
createIPCServer
();
disposables
.
push
(
ipc
);
env
=
{
...
env
,
...
ipc
.
getEnv
()
};
}
catch
{
// noop
}
if
(
ipc
)
{
const
askpass
=
new
Askpass
(
ipc
);
disposables
.
push
(
askpass
);
env
=
{
...
env
,
...
askpass
.
getEnv
()
};
}
else
{
env
=
{
...
env
,
...
Askpass
.
getDisabledEnv
()
};
}
const
git
=
new
Git
({
gitPath
:
info
.
path
,
version
:
info
.
version
,
env
});
const
model
=
new
Model
(
git
,
context
.
globalState
,
outputChannel
);
const
git
=
new
Git
({
gitPath
:
info
.
path
,
version
:
info
.
version
,
env
:
askpass
.
getEnv
()
});
const
model
=
new
Model
(
git
,
askpass
,
context
.
globalState
,
outputChannel
);
disposables
.
push
(
model
);
const
onRepository
=
()
=>
commands
.
executeCommand
(
'
setContext
'
,
'
gitOpenRepositoryCount
'
,
`
${
model
.
repositories
.
length
}
`
);
...
...
extensions/git/src/model.ts
浏览文件 @
c7fec928
...
...
@@ -12,7 +12,8 @@ import * as path from 'path';
import
*
as
fs
from
'
fs
'
;
import
*
as
nls
from
'
vscode-nls
'
;
import
{
fromGitUri
}
from
'
./uri
'
;
import
{
GitErrorCodes
,
APIState
as
State
,
RemoteSourceProvider
}
from
'
./api/git
'
;
import
{
GitErrorCodes
,
APIState
as
State
,
RemoteSourceProvider
,
CredentialsProvider
}
from
'
./api/git
'
;
import
{
Askpass
}
from
'
./askpass
'
;
const
localize
=
nls
.
loadMessageBundle
();
...
...
@@ -78,7 +79,7 @@ export class Model {
private
disposables
:
Disposable
[]
=
[];
constructor
(
readonly
git
:
Git
,
private
globalState
:
Memento
,
private
outputChannel
:
OutputChannel
)
{
constructor
(
readonly
git
:
Git
,
private
readonly
askpass
:
Askpass
,
private
globalState
:
Memento
,
private
outputChannel
:
OutputChannel
)
{
workspace
.
onDidChangeWorkspaceFolders
(
this
.
onDidChangeWorkspaceFolders
,
this
,
this
.
disposables
);
window
.
onDidChangeVisibleTextEditors
(
this
.
onDidChangeVisibleTextEditors
,
this
,
this
.
disposables
);
workspace
.
onDidChangeConfiguration
(
this
.
onDidChangeConfiguration
,
this
,
this
.
disposables
);
...
...
@@ -454,6 +455,10 @@ export class Model {
return
toDisposable
(()
=>
this
.
remoteProviders
.
delete
(
provider
));
}
registerCredentialsProvider
(
provider
:
CredentialsProvider
):
Disposable
{
return
this
.
askpass
.
registerCredentialsProvider
(
provider
);
}
getRemoteProviders
():
RemoteSourceProvider
[]
{
return
[...
this
.
remoteProviders
.
values
()];
}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录