Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
掘金者说
vscode
提交
d298248b
V
vscode
项目概览
掘金者说
/
vscode
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
V
vscode
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
d298248b
编写于
5月 15, 2018
作者:
P
Peng Lyu
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
git refactor
上级
d1ddcb49
变更
16
隐藏空白更改
内联
并排
Showing
16 changed file
with
398 addition
and
417 deletion
+398
-417
extensions/git-extended/README.md
extensions/git-extended/README.md
+2
-5
extensions/git-extended/src/common/diff.ts
extensions/git-extended/src/common/diff.ts
+32
-29
extensions/git-extended/src/common/log.ts
extensions/git-extended/src/common/log.ts
+0
-86
extensions/git-extended/src/common/models/diffHunk.ts
extensions/git-extended/src/common/models/diffHunk.ts
+38
-3
extensions/git-extended/src/common/models/diffLine.ts
extensions/git-extended/src/common/models/diffLine.ts
+0
-51
extensions/git-extended/src/common/models/githubRef.ts
extensions/git-extended/src/common/models/githubRef.ts
+5
-5
extensions/git-extended/src/common/models/model.ts
extensions/git-extended/src/common/models/model.ts
+0
-11
extensions/git-extended/src/common/models/protocol.ts
extensions/git-extended/src/common/models/protocol.ts
+138
-0
extensions/git-extended/src/common/models/pullRequestModel.ts
...nsions/git-extended/src/common/models/pullRequestModel.ts
+10
-10
extensions/git-extended/src/common/models/remote.ts
extensions/git-extended/src/common/models/remote.ts
+14
-8
extensions/git-extended/src/common/models/repository.ts
extensions/git-extended/src/common/models/repository.ts
+29
-13
extensions/git-extended/src/common/pullRequestGitHelper.ts
extensions/git-extended/src/common/pullRequestGitHelper.ts
+117
-127
extensions/git-extended/src/common/remote.ts
extensions/git-extended/src/common/remote.ts
+0
-56
extensions/git-extended/src/credentials.ts
extensions/git-extended/src/credentials.ts
+1
-1
extensions/git-extended/src/prView/prProvider.ts
extensions/git-extended/src/prView/prProvider.ts
+1
-1
extensions/git-extended/src/review/reviewManager.ts
extensions/git-extended/src/review/reviewManager.ts
+11
-11
未找到文件。
extensions/git-extended/README.md
浏览文件 @
d298248b
#
Git Extended
#
VSCode Pull Request Support for GitHub
Experimental enhanced Git/Review/PR experience.
## Notices
Uses code from github desktop: https://github.com/desktop/desktop
\ No newline at end of file
Experimental enhanced Git/Review/PR experience.
\ No newline at end of file
extensions/git-extended/src/common/diff.ts
浏览文件 @
d298248b
...
...
@@ -8,8 +8,7 @@ import { getFileContent, writeTmpFile } from './file';
import
{
GitChangeType
,
RichFileChange
}
from
'
./models/file
'
;
import
{
Repository
}
from
'
./models/repository
'
;
import
{
Comment
}
from
'
./models/comment
'
;
import
{
DiffHunk
}
from
'
./models/diffHunk
'
;
import
{
getDiffChangeType
,
DiffLine
,
DiffChangeType
}
from
'
./models/diffLine
'
;
import
{
DiffHunk
,
getDiffChangeType
,
DiffLine
,
DiffChangeType
}
from
'
./models/diffHunk
'
;
export
const
MODIFY_DIFF_INFO
=
/diff --git a
\/(\S
+
)
b
\/(\S
+
)
.*
\n
*index.*
\n
*-
{3}
.*
\n
*
\+{3}
.*
\n
*
((
.*
\n
*
)
+
)
/
;
export
const
NEW_FILE_INFO
=
/diff --git a
\/(\S
+
)
b
\/(\S
+
)
.*
\n
*new file mode .*
\n
index.*
\n
*-
{3}
.*
\n
*
\+{3}
.*
\n
*
((
.*
\n
*
)
+
)
/
;
...
...
@@ -53,44 +52,47 @@ export function* parseDiffHunk(diffHunkPatch: string): IterableIterator<DiffHunk
let
itr
=
lineReader
.
next
();
let
diffHunk
:
DiffHunk
=
null
;
let
diffLine
=
-
1
;
let
positionInHunk
=
-
1
;
let
oldLine
=
-
1
;
let
newLine
=
-
1
;
while
(
!
itr
.
done
)
{
le
t
line
=
itr
.
value
;
cons
t
line
=
itr
.
value
;
if
(
DIFF_HUNK_HEADER
.
test
(
line
))
{
if
(
diffHunk
)
{
yield
diffHunk
;
diffHunk
=
null
;
}
if
(
diffLine
===
-
1
)
{
diffLine
=
0
;
if
(
positionInHunk
===
-
1
)
{
positionInHunk
=
0
;
}
le
t
matches
=
DIFF_HUNK_HEADER
.
exec
(
line
);
le
t
oriStartLine
=
oldLine
=
Number
(
matches
[
1
]);
le
t
oriLen
=
Number
(
matches
[
3
])
|
0
;
le
t
newStartLine
=
newLine
=
Number
(
matches
[
5
]);
le
t
newLen
=
Number
(
matches
[
7
])
|
0
;
cons
t
matches
=
DIFF_HUNK_HEADER
.
exec
(
line
);
cons
t
oriStartLine
=
oldLine
=
Number
(
matches
[
1
]);
cons
t
oriLen
=
Number
(
matches
[
3
])
|
0
;
cons
t
newStartLine
=
newLine
=
Number
(
matches
[
5
]);
cons
t
newLen
=
Number
(
matches
[
7
])
|
0
;
diffHunk
=
new
DiffHunk
(
oriStartLine
,
oriLen
,
newStartLine
,
newLen
,
diffLine
);
diffHunk
=
new
DiffHunk
(
oriStartLine
,
oriLen
,
newStartLine
,
newLen
,
positionInHunk
);
}
else
if
(
diffHunk
!==
null
)
{
let
type
=
getDiffChangeType
(
line
[
0
]
);
let
type
=
getDiffChangeType
(
line
);
if
(
type
!==
DiffChangeType
.
Control
)
{
diffHunk
.
Lines
.
push
(
new
DiffLine
(
type
,
type
!==
DiffChangeType
.
Add
?
oldLine
:
-
1
,
if
(
type
===
DiffChangeType
.
Control
)
{
if
(
diffHunk
.
diffLines
&&
diffHunk
.
diffLines
.
length
)
{
diffHunk
.
diffLines
[
diffHunk
.
diffLines
.
length
-
1
].
endwithLineBreak
=
false
;
}
}
else
{
diffHunk
.
diffLines
.
push
(
new
DiffLine
(
type
,
type
!==
DiffChangeType
.
Add
?
oldLine
:
-
1
,
type
!==
DiffChangeType
.
Delete
?
newLine
:
-
1
,
diffLine
,
positionInHunk
,
line
));
var
lineCount
=
1
;
lineCount
+=
countCarriageReturns
(
line
);
let
lineCount
=
1
+
countCarriageReturns
(
line
);
switch
(
type
)
{
case
DiffChangeType
.
None
:
case
DiffChangeType
.
Context
:
oldLine
+=
lineCount
;
newLine
+=
lineCount
;
break
;
...
...
@@ -103,8 +105,9 @@ export function* parseDiffHunk(diffHunkPatch: string): IterableIterator<DiffHunk
}
}
}
if
(
diffLine
!==
-
1
)
{
++
diffLine
;
if
(
positionInHunk
!==
-
1
)
{
++
positionInHunk
;
}
itr
=
lineReader
.
next
();
}
...
...
@@ -120,9 +123,9 @@ export function getDiffLineByPosition(prPatch: string, diffLineNumber: number):
while
(
!
prDiffIter
.
done
)
{
let
diffHunk
=
prDiffIter
.
value
;
for
(
let
i
=
0
;
i
<
diffHunk
.
Lines
.
length
;
i
++
)
{
if
(
diffHunk
.
Lines
[
i
].
diffLineNumber
===
diffLineNumber
)
{
return
diffHunk
.
Lines
[
i
];
for
(
let
i
=
0
;
i
<
diffHunk
.
diff
Lines
.
length
;
i
++
)
{
if
(
diffHunk
.
diffLines
[
i
].
positionInHunk
===
diffLineNumber
)
{
return
diffHunk
.
diff
Lines
[
i
];
}
}
...
...
@@ -159,7 +162,7 @@ export function mapHeadLineToDiffHunkPosition(prPatch: string, localDiff: string
while
(
!
prDiffIter
.
done
)
{
let
diffHunk
=
prDiffIter
.
value
;
if
(
diffHunk
.
newLineNumber
<=
lineInPRDiff
&&
diffHunk
.
newLineNumber
+
diffHunk
.
newLength
-
1
>=
lineInPRDiff
)
{
positionInDiffHunk
=
lineInPRDiff
-
diffHunk
.
newLineNumber
+
diffHunk
.
diffLine
+
1
;
positionInDiffHunk
=
lineInPRDiff
-
diffHunk
.
newLineNumber
+
diffHunk
.
positionInHunk
+
1
;
break
;
}
...
...
@@ -209,13 +212,13 @@ async function parseModifiedHunkComplete(originalContent, patch, a, b) {
lastCommonLine
=
oriStartLine
+
diffHunk
.
oldLength
-
1
;
for
(
let
j
=
0
;
j
<
diffHunk
.
Lines
.
length
;
j
++
)
{
let
diffLine
=
diffHunk
.
Lines
[
j
];
for
(
let
j
=
0
;
j
<
diffHunk
.
diff
Lines
.
length
;
j
++
)
{
let
diffLine
=
diffHunk
.
diff
Lines
[
j
];
if
(
diffLine
.
type
===
DiffChangeType
.
Delete
)
{
}
else
if
(
diffLine
.
type
===
DiffChangeType
.
Add
)
{
right
.
push
(
diffLine
.
content
.
substr
(
1
)
);
right
.
push
(
diffLine
.
text
);
}
else
{
let
codeInFirstLine
=
diffLine
.
content
.
substr
(
1
)
;
let
codeInFirstLine
=
diffLine
.
text
;
right
.
push
(
codeInFirstLine
);
}
}
...
...
extensions/git-extended/src/common/log.ts
已删除
100644 → 0
浏览文件 @
d1ddcb49
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/* --------------------------------------------------------------------------------------------
* Includes code from github/desktop, obtained from
* https://github.com/desktop/desktop/blob/0ce0de27f4eff526c073a159ce36ac9b27407e5c/app/src/lib/git/log.ts
* ------------------------------------------------------------------------------------------ */
import
{
Repository
}
from
'
./models/repository
'
;
import
{
Commit
}
from
'
./models/commit
'
;
import
{
GitProcess
}
from
'
dugite
'
;
export
async
function
getParentCommit
(
repository
:
Repository
,
sha
:
string
):
Promise
<
string
>
{
const
result
=
await
GitProcess
.
exec
(
[
'
rev-list
'
,
'
--parents
'
,
'
-n
'
,
'
1
'
,
sha
],
repository
.
path
);
let
commits
=
result
.
stdout
.
split
(
'
'
);
if
(
commits
.
length
>
2
)
{
return
commits
[
1
];
}
else
{
return
null
;
}
}
export
async
function
getCommits
(
repository
:
Repository
,
revisionRange
:
string
,
limit
:
number
,
additionalArgs
:
ReadonlyArray
<
string
>
=
[]):
Promise
<
Commit
[]
>
{
const
delimiter
=
'
1F
'
;
const
delimiterString
=
String
.
fromCharCode
(
parseInt
(
delimiter
,
16
));
const
prettyFormat
=
[
'
%H
'
,
// SHA
'
%s
'
,
// summary
'
%P
'
,
// parent SHAs
].
join
(
`%x
${
delimiter
}
`
);
const
result
=
await
GitProcess
.
exec
([
'
log
'
,
revisionRange
,
`--max-count=
${
limit
}
`
,
`--pretty=
${
prettyFormat
}
`
,
'
-z
'
,
...
additionalArgs
,
],
repository
.
path
);
const
out
=
result
.
stdout
;
const
lines
=
out
.
split
(
'
\
0
'
);
lines
.
splice
(
-
1
,
1
);
const
commits
=
lines
.
map
(
line
=>
{
const
pieces
=
line
.
split
(
delimiterString
);
const
sha
=
pieces
[
0
];
const
summary
=
pieces
[
1
];
const
shaList
=
pieces
[
2
];
const
parentSHAs
=
shaList
.
length
?
shaList
.
split
(
'
'
)
:
[];
return
new
Commit
(
sha
,
summary
,
parentSHAs
);
});
return
commits
;
}
export
async
function
isWorkingTreeClean
(
repository
:
Repository
):
Promise
<
boolean
>
{
const
result
=
await
GitProcess
.
exec
(
[
'
diff-index
'
,
'
--quiet
'
,
'
HEAD
'
,
'
--
'
],
repository
.
path
);
let
exitCode
=
result
.
exitCode
;
if
(
exitCode
!==
0
)
{
return
false
;
}
else
{
return
true
;
}
}
\ No newline at end of file
extensions/git-extended/src/common/models/diffHunk.ts
浏览文件 @
d298248b
...
...
@@ -3,16 +3,51 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
{
DiffLine
}
from
'
./diffLine
'
;
export
enum
DiffChangeType
{
Context
,
Add
,
Delete
,
Control
}
export
class
DiffLine
{
public
get
raw
():
string
{
return
this
.
_raw
;
}
public
get
text
():
string
{
return
this
.
_raw
.
substr
(
1
);
}
public
endwithLineBreak
:
boolean
=
true
;
constructor
(
public
type
:
DiffChangeType
,
public
oldLineNumber
:
number
,
/* 1 based */
public
newLineNumber
:
number
,
/* 1 based */
public
positionInHunk
:
number
,
private
_raw
:
string
)
{
}
}
export
function
getDiffChangeType
(
text
:
string
)
{
let
c
=
text
[
0
];
switch
(
c
)
{
case
'
'
:
return
DiffChangeType
.
Context
;
case
'
+
'
:
return
DiffChangeType
.
Add
;
case
'
-
'
:
return
DiffChangeType
.
Delete
;
case
'
\\
'
:
return
DiffChangeType
.
Control
;
}
}
export
class
DiffHunk
{
public
Lines
:
DiffLine
[]
=
[];
public
diff
Lines
:
DiffLine
[]
=
[];
constructor
(
public
oldLineNumber
:
number
,
public
oldLength
:
number
,
public
newLineNumber
:
number
,
public
newLength
:
number
,
public
diffLine
:
number
public
positionInHunk
:
number
)
{
}
}
\ No newline at end of file
extensions/git-extended/src/common/models/diffLine.ts
已删除
100644 → 0
浏览文件 @
d1ddcb49
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/* --------------------------------------------------------------------------------------------
* Includes code from github/VisualStudio project, obtained from
* https://github.com/github/VisualStudio/blob/master/src/GitHub.Exports/Models/DiffLine.cs
* ------------------------------------------------------------------------------------------ */
export
enum
DiffChangeType
{
None
,
Add
,
Delete
,
Control
}
export
class
DiffLine
{
// Was the line added, deleted or unchanged.
type
:
DiffChangeType
;
// Gets the old 1-based line number.
oldLineNumber
:
number
=
-
1
;
// Gets the new 1-based line number.
newLineNumber
:
number
=
-
1
;
// Gets the unified diff line number where the first chunk header is line 0.
diffLineNumber
:
number
=
-
1
;
// Gets the content of the diff line (including +, - or space).
content
:
String
;
constructor
(
type
:
DiffChangeType
,
oldLineNumber
:
number
,
newLineNumber
:
number
,
diffLineNumber
:
number
,
content
:
string
)
{
this
.
type
=
type
;
this
.
oldLineNumber
=
oldLineNumber
;
this
.
newLineNumber
=
newLineNumber
;
this
.
diffLineNumber
=
diffLineNumber
;
this
.
content
=
content
;
}
}
export
function
getDiffChangeType
(
text
:
string
)
{
let
c
=
text
[
0
];
switch
(
c
)
{
case
'
'
:
return
DiffChangeType
.
None
;
case
'
+
'
:
return
DiffChangeType
.
Add
;
case
'
-
'
:
return
DiffChangeType
.
Delete
;
case
'
\\
'
:
return
DiffChangeType
.
Control
;
}
}
\ No newline at end of file
extensions/git-extended/src/common/models/git
ReferenceModel
.ts
→
extensions/git-extended/src/common/models/git
hubRef
.ts
浏览文件 @
d298248b
...
...
@@ -3,16 +3,16 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
{
UriString
}
from
'
./uriString
'
;
import
{
Protocol
}
from
'
./protocol
'
;
export
class
Git
ReferenceModel
{
public
repositoryCloneUrl
:
UriString
;
export
class
Git
HubRef
{
public
repositoryCloneUrl
:
Protocol
;
constructor
(
public
ref
:
string
,
public
label
:
string
,
public
sha
:
string
,
repositoryCloneUrl
:
string
)
{
this
.
repositoryCloneUrl
=
new
UriString
(
repositoryCloneUrl
);
this
.
repositoryCloneUrl
=
new
Protocol
(
repositoryCloneUrl
);
}
}
\ No newline at end of file
}
extensions/git-extended/src/common/models/model.ts
已删除
100644 → 0
浏览文件 @
d1ddcb49
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
{
Repository
}
from
'
./repository
'
;
export
class
Model
{
constructor
(
repository
:
Repository
)
{
}
}
\ No newline at end of file
extensions/git-extended/src/common/models/
uriString
.ts
→
extensions/git-extended/src/common/models/
protocol
.ts
浏览文件 @
d298248b
...
...
@@ -3,22 +3,35 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/* --------------------------------------------------------------------------------------------
* Includes code from github/VisualStudio project, obtained from
* https://github.com/github/VisualStudio/blob/master/src/GitHub.Exports/Primitives/UriString.cs
* ------------------------------------------------------------------------------------------ */
import
*
as
vscode
from
'
vscode
'
;
const
sshRegex
=
/^.+@
(([
.*?
]
|
[
a-z0-9-.
]
+
?))(
:
(
.*
?))?(\/(
.*
)(
.git
)?)?
$/i
;
export
class
UriString
{
public
host
:
string
;
export
enum
ProtocolType
{
Local
,
HTTP
,
SSH
,
GIT
,
OTHER
}
const
gitProtocolRegex
=
[
new
RegExp
(
'
^git@(.+):(.+)/(.+?)(?:/|.git)?$
'
),
new
RegExp
(
'
^git:(.+)/(.+)/(.+?)(?:/|.git)?$
'
)
];
const
sshProtocolRegex
=
[
new
RegExp
(
'
^ssh://git@(.+)/(.+)/(.+?)(?:/|.git)?$
'
)
];
export
class
Protocol
{
public
type
:
ProtocolType
=
ProtocolType
.
OTHER
;
public
host
:
string
=
''
;
public
owner
:
string
;
public
owner
:
string
=
''
;
public
repositoryName
:
string
;
public
repositoryName
:
string
=
''
;
public
nameWithOwner
:
string
;
public
get
nameWithOwner
():
string
{
return
this
.
owner
?
`
${
this
.
owner
}
/
${
this
.
repositoryName
}
`
:
this
.
repositoryName
;
}
public
isFileUri
:
boolean
;
...
...
@@ -30,56 +43,51 @@ export class UriString {
constructor
(
uriString
:
string
)
{
let
parseUriSuccess
=
false
;
try
{
this
.
url
=
vscode
.
Uri
.
parse
(
uriString
);
parseUriSuccess
=
true
;
if
(
this
.
url
.
scheme
===
'
file
'
)
{
this
.
setFilePath
(
this
.
url
);
}
else
{
this
.
setUri
(
this
.
url
);
this
.
type
=
ProtocolType
.
Local
;
this
.
repositoryName
=
this
.
getRepositoryName
(
this
.
url
.
path
);
return
;
}
if
(
this
.
url
.
scheme
===
'
https
'
||
this
.
url
.
scheme
===
'
http
'
)
{
this
.
type
=
ProtocolType
.
HTTP
;
this
.
host
=
this
.
url
.
authority
;
this
.
repositoryName
=
this
.
getRepositoryName
(
this
.
url
.
path
);
this
.
owner
=
this
.
getOwnerName
(
this
.
url
.
path
);
return
;
}
}
catch
(
e
)
{
}
if
(
!
parseUriSuccess
)
{
try
{
let
matches
=
sshRegex
.
exec
(
uriString
);
if
(
matches
)
{
this
.
host
=
matches
[
1
];
this
.
owner
=
matches
[
4
];
this
.
repositoryName
=
this
.
getRepositoryName
(
matches
[
6
]);
this
.
isScpUri
=
true
;
}
else
{
this
.
setFilePath2
(
uriString
);
try
{
for
(
const
regex
of
gitProtocolRegex
)
{
const
result
=
uriString
.
match
(
regex
);
if
(
!
result
)
{
continue
;
}
}
catch
(
e
)
{
}
}
if
(
this
.
repositoryName
)
{
this
.
nameWithOwner
=
this
.
owner
?
`
${
this
.
owner
}
/
${
this
.
repositoryName
}
`
:
this
.
repositoryName
;
}
}
setUri
(
uri
:
vscode
.
Uri
)
{
this
.
host
=
uri
.
authority
;
this
.
repositoryName
=
this
.
getRepositoryName
(
uri
.
path
);
this
.
owner
=
this
.
getOwnerName
(
uri
.
path
);
}
this
.
host
=
result
[
1
];
this
.
owner
=
result
[
2
];
this
.
repositoryName
=
result
[
3
];
this
.
type
=
ProtocolType
.
GIT
;
return
;
}
setFilePath
(
uri
:
vscode
.
Uri
)
{
this
.
host
=
''
;
this
.
owner
=
''
;
this
.
repositoryName
=
this
.
getRepositoryName
(
uri
.
path
);
this
.
isFileUri
=
true
;
}
for
(
const
regex
of
sshProtocolRegex
)
{
const
result
=
uriString
.
match
(
regex
);
if
(
!
result
)
{
continue
;
}
setFilePath2
(
path
:
string
)
{
this
.
host
=
''
;
this
.
owner
=
''
;
this
.
repositoryName
=
this
.
getRepositoryName
(
path
);
this
.
isFileUri
=
true
;
this
.
host
=
result
[
1
];
this
.
owner
=
result
[
2
];
this
.
repositoryName
=
result
[
3
];
this
.
type
=
ProtocolType
.
SSH
;
return
;
}
}
catch
(
e
)
{
}
}
getRepositoryName
(
path
:
string
)
{
...
...
@@ -103,8 +111,12 @@ export class UriString {
return
null
;
}
toRepositoryUrl
(
owner
:
string
=
null
):
vscode
.
Uri
{
if
(
!
this
.
isScpUri
&&
(
!
this
.
url
||
this
.
isFileUri
))
{
normalizeUri
():
vscode
.
Uri
{
if
(
this
.
type
===
ProtocolType
.
OTHER
&&
!
this
.
url
)
{
return
null
;
}
if
(
this
.
isFileUri
)
{
return
this
.
url
;
}
...
...
@@ -113,16 +125,14 @@ export class UriString {
scheme
=
this
.
url
.
scheme
;
}
let
nameWithOwner
=
this
.
owner
?
`
${
this
.
owner
}
/
${
this
.
repositoryName
}
`
:
this
.
repositoryName
;
try
{
return
vscode
.
Uri
.
parse
(
`
${
scheme
}
://
${
this
.
host
}
/
${
nameWithOwner
}
`
);
return
vscode
.
Uri
.
parse
(
`
${
scheme
}
://
${
this
.
host
}
/
${
this
.
nameWithOwner
}
`
);
}
catch
(
e
)
{
return
null
;
}
}
equals
(
other
:
UriString
)
{
return
this
.
toRepositoryUrl
().
toString
().
toLocaleLowerCase
()
===
other
.
toRepositoryUrl
().
toString
().
toLocaleLowerCase
();
equals
(
other
:
Protocol
)
{
return
this
.
normalizeUri
().
toString
().
toLocaleLowerCase
()
===
other
.
normalizeUri
().
toString
().
toLocaleLowerCase
();
}
}
\ No newline at end of file
extensions/git-extended/src/common/models/pullRequestModel.ts
浏览文件 @
d298248b
...
...
@@ -7,7 +7,7 @@ import { Remote } from './remote';
import
{
parseComments
}
from
'
../comment
'
;
import
{
Comment
}
from
'
./comment
'
;
import
{
IAccount
}
from
'
./account
'
;
import
{
Git
ReferenceModel
}
from
'
./gitReferenceModel
'
;
import
{
Git
HubRef
}
from
'
./githubRef
'
;
export
enum
PRType
{
RequestReview
=
0
,
...
...
@@ -43,8 +43,8 @@ export class PullRequestModel {
return
this
.
state
===
PullRequestStateEnum
.
Merged
;
}
public
head
:
Git
ReferenceModel
;
public
base
:
Git
ReferenceModel
;
public
head
:
Git
HubRef
;
public
base
:
Git
HubRef
;
constructor
(
public
readonly
otcokit
:
any
,
public
readonly
remote
:
Remote
,
public
prItem
:
any
)
{
this
.
prNumber
=
prItem
.
number
;
...
...
@@ -81,14 +81,14 @@ export class PullRequestModel {
this
.
commentCount
=
prItem
.
comments
;
this
.
commitCount
=
prItem
.
commits
;
this
.
head
=
new
Git
ReferenceModel
(
prItem
.
head
.
ref
,
prItem
.
head
.
label
,
prItem
.
head
.
sha
,
prItem
.
head
.
repo
.
clone_url
);
this
.
base
=
new
Git
ReferenceModel
(
prItem
.
base
.
ref
,
prItem
.
base
.
label
,
prItem
.
base
.
sha
,
prItem
.
base
.
repo
.
clone_url
);
this
.
head
=
new
Git
HubRef
(
prItem
.
head
.
ref
,
prItem
.
head
.
label
,
prItem
.
head
.
sha
,
prItem
.
head
.
repo
.
clone_url
);
this
.
base
=
new
Git
HubRef
(
prItem
.
base
.
ref
,
prItem
.
base
.
label
,
prItem
.
base
.
sha
,
prItem
.
base
.
repo
.
clone_url
);
}
async
getFiles
()
{
const
{
data
}
=
await
this
.
otcokit
.
pullRequests
.
getFiles
({
owner
:
this
.
remote
.
owner
,
repo
:
this
.
remote
.
n
ame
,
repo
:
this
.
remote
.
repositoryN
ame
,
number
:
this
.
prItem
.
number
});
...
...
@@ -100,7 +100,7 @@ export class PullRequestModel {
// this one is from search results, which is not complete.
const
{
data
}
=
await
this
.
otcokit
.
pullRequests
.
get
({
owner
:
this
.
remote
.
owner
,
repo
:
this
.
remote
.
n
ame
,
repo
:
this
.
remote
.
repositoryN
ame
,
number
:
this
.
prItem
.
number
});
this
.
prItem
=
data
;
...
...
@@ -112,7 +112,7 @@ export class PullRequestModel {
async
getComments
():
Promise
<
Comment
[]
>
{
const
reviewData
=
await
this
.
otcokit
.
pullRequests
.
getComments
({
owner
:
this
.
remote
.
owner
,
repo
:
this
.
remote
.
n
ame
,
repo
:
this
.
remote
.
repositoryN
ame
,
number
:
this
.
prItem
.
number
,
per_page
:
100
});
...
...
@@ -123,7 +123,7 @@ export class PullRequestModel {
async
createCommentReply
(
body
:
string
,
reply_to
:
string
)
{
let
ret
=
await
this
.
otcokit
.
pullRequests
.
createCommentReply
({
owner
:
this
.
remote
.
owner
,
repo
:
this
.
remote
.
n
ame
,
repo
:
this
.
remote
.
repositoryN
ame
,
number
:
this
.
prItem
.
number
,
body
:
body
,
in_reply_to
:
reply_to
...
...
@@ -135,7 +135,7 @@ export class PullRequestModel {
async
createComment
(
body
:
string
,
path
:
string
,
position
:
number
)
{
let
ret
=
await
this
.
otcokit
.
pullRequests
.
createComment
({
owner
:
this
.
remote
.
owner
,
repo
:
this
.
remote
.
n
ame
,
repo
:
this
.
remote
.
repositoryN
ame
,
number
:
this
.
prItem
.
number
,
body
:
body
,
commit_id
:
this
.
prItem
.
head
.
sha
,
...
...
extensions/git-extended/src/common/models/remote.ts
浏览文件 @
d298248b
...
...
@@ -3,29 +3,35 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
{
Protocol
}
from
'
./protocol
'
;
export
class
Remote
{
public
get
host
():
string
{
return
this
.
gitProtocol
.
host
;
}
public
get
owner
():
string
{
return
this
.
gitProtocol
.
owner
;
}
public
get
repositoryName
():
string
{
return
this
.
gitProtocol
.
repositoryName
;
}
constructor
(
public
readonly
remoteName
:
string
,
public
readonly
url
:
string
,
public
readonly
hostname
:
string
,
public
readonly
owner
:
string
,
public
readonly
name
:
string
public
readonly
gitProtocol
:
Protocol
,
)
{
}
equals
(
remote
:
Remote
):
boolean
{
if
(
this
.
remoteName
!==
remote
.
remoteName
)
{
return
false
;
}
// if (this.url !== remote.url) {
// return false;
// }
if
(
this
.
hostname
!==
remote
.
hostname
)
{
if
(
this
.
host
!==
remote
.
host
)
{
return
false
;
}
if
(
this
.
owner
!==
remote
.
owner
)
{
return
false
;
}
if
(
this
.
name
!==
remote
.
n
ame
)
{
if
(
this
.
repositoryName
!==
remote
.
repositoryN
ame
)
{
return
false
;
}
...
...
extensions/git-extended/src/common/models/repository.ts
浏览文件 @
d298248b
...
...
@@ -7,11 +7,11 @@ import * as vscode from 'vscode';
import
{
Remote
}
from
'
./remote
'
;
import
{
GitProcess
}
from
'
dugite
'
;
import
{
uniqBy
,
anyEvent
,
filterEvent
,
isDescendant
}
from
'
../util
'
;
import
{
parseRemote
}
from
'
../remote
'
;
import
{
CredentialStore
}
from
'
../../credentials
'
;
import
{
PullRequestModel
,
PRType
}
from
'
./pullRequestModel
'
;
import
{
UriString
}
from
'
./uriString
'
;
import
{
Protocol
}
from
'
./protocol
'
;
import
{
GitError
,
GitErrorCodes
}
from
'
./gitError
'
;
import
{
PullRequestGitHelper
}
from
'
../pullRequestGitHelper
'
;
export
enum
RefType
{
Head
,
...
...
@@ -43,7 +43,7 @@ export class Repository {
private
_onDidRunGitStatus
=
new
vscode
.
EventEmitter
<
void
>
();
readonly
onDidRunGitStatus
:
vscode
.
Event
<
void
>
=
this
.
_onDidRunGitStatus
.
event
;
public
githubRepositories
?:
GitHubRepository
[];
public
githubRepositories
?:
GitHubRepository
[]
=
[]
;
private
_HEAD
:
Branch
|
undefined
;
get
HEAD
():
Branch
|
undefined
{
...
...
@@ -61,8 +61,8 @@ export class Repository {
}
// todo
private
_cloneUrl
:
UriString
;
get
cloneUrl
():
UriString
{
private
_cloneUrl
:
Protocol
;
get
cloneUrl
():
Protocol
{
return
this
.
_cloneUrl
;
}
...
...
@@ -116,7 +116,7 @@ export class Repository {
if
(
this
.
_HEAD
.
upstream
&&
this
.
_HEAD
.
upstream
.
remote
)
{
let
currentRemote
=
this
.
_remotes
.
filter
(
remote
=>
remote
.
remoteName
===
this
.
_HEAD
.
upstream
.
remote
);
if
(
currentRemote
&&
currentRemote
.
length
)
{
this
.
_cloneUrl
=
new
UriString
(
currentRemote
[
0
].
url
);
this
.
_cloneUrl
=
new
Protocol
(
currentRemote
[
0
].
url
);
}
}
...
...
@@ -126,7 +126,13 @@ export class Repository {
async
connectGitHub
(
credentialStore
:
CredentialStore
)
{
let
ret
:
GitHubRepository
[]
=
[];
await
Promise
.
all
(
this
.
remotes
.
map
(
async
remote
=>
{
let
isRemoteForPR
=
await
PullRequestGitHelper
.
isRemoteCreatedForPullRequest
(
this
,
remote
.
remoteName
);
if
(
isRemoteForPR
)
{
return
;
}
let
octo
=
await
credentialStore
.
getOctokit
(
remote
);
if
(
octo
)
{
ret
.
push
(
new
GitHubRepository
(
remote
,
octo
));
}
...
...
@@ -135,12 +141,12 @@ export class Repository {
this
.
githubRepositories
=
ret
;
}
async
fetch
(
remoteName
:
string
,
branch
:
string
)
{
async
fetch
(
remoteName
:
string
,
branch
?
:
string
)
{
const
result
=
await
GitProcess
.
exec
(
[
'
fetch
'
,
remoteName
,
branch
branch
?
branch
:
''
],
this
.
path
);
...
...
@@ -375,7 +381,7 @@ export class GitHubRepository {
if
(
prType
===
PRType
.
All
)
{
let
result
=
await
this
.
octokit
.
pullRequests
.
getAll
({
owner
:
this
.
remote
.
owner
,
repo
:
this
.
remote
.
n
ame
,
repo
:
this
.
remote
.
repositoryN
ame
,
});
let
ret
=
result
.
data
.
map
(
item
=>
{
if
(
!
item
.
head
.
repo
)
{
...
...
@@ -389,7 +395,7 @@ export class GitHubRepository {
const
user
=
await
this
.
octokit
.
users
.
get
();
const
{
data
}
=
await
this
.
octokit
.
search
.
issues
({
q
:
this
.
getPRFetchQuery
(
this
.
remote
.
owner
,
this
.
remote
.
n
ame
,
user
.
data
.
login
,
prType
)
q
:
this
.
getPRFetchQuery
(
this
.
remote
.
owner
,
this
.
remote
.
repositoryN
ame
,
user
.
data
.
login
,
prType
)
});
let
promises
=
[];
...
...
@@ -397,7 +403,7 @@ export class GitHubRepository {
promises
.
push
(
new
Promise
(
async
(
resolve
,
reject
)
=>
{
let
prData
=
await
this
.
octokit
.
pullRequests
.
get
({
owner
:
this
.
remote
.
owner
,
repo
:
this
.
remote
.
n
ame
,
repo
:
this
.
remote
.
repositoryN
ame
,
number
:
item
.
number
});
resolve
(
prData
);
...
...
@@ -419,7 +425,7 @@ export class GitHubRepository {
async
getPullRequest
(
id
:
number
)
{
let
{
data
}
=
await
this
.
octokit
.
pullRequests
.
get
({
owner
:
this
.
remote
.
owner
,
repo
:
this
.
remote
.
n
ame
,
repo
:
this
.
remote
.
repositoryN
ame
,
number
:
id
});
if
(
!
data
.
head
.
repo
)
{
...
...
@@ -453,4 +459,14 @@ export class GitHubRepository {
return
`is:open
${
filter
}
type:pr repo:
${
owner
}
/
${
repo
}
`
;
}
}
\ No newline at end of file
}
function
parseRemote
(
remoteName
:
string
,
url
:
string
):
Remote
|
null
{
let
gitProtocol
=
new
Protocol
(
url
);
if
(
gitProtocol
.
host
)
{
return
new
Remote
(
remoteName
,
url
,
gitProtocol
);
}
return
null
;
}
extensions/git-extended/src/common/pullRequestGitHelper.ts
浏览文件 @
d298248b
...
...
@@ -3,143 +3,110 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/* --------------------------------------------------------------------------------------------
* Includes code from github/VisualStudio project, obtained from
* https://github.com/github/VisualStudio/blob/master/src/GitHub.App/Services/PullRequestService.cs
* ------------------------------------------------------------------------------------------ */
import
{
Repository
}
from
'
../common/models/repository
'
;
import
{
PullRequestModel
}
from
'
../common/models/pullRequestModel
'
;
import
{
UriString
}
from
'
../common/models/uriString
'
;
import
{
Protocol
}
from
'
../common/models/protocol
'
;
import
{
Remote
}
from
'
./models/remote
'
;
const
InvalidBranchCharsRegex
=
/
[^
0-9A-Za-z
\-]
/g
;
const
SettingCreatedByGHfVSC
=
'
created-by-ghfvsc
'
;
const
SettingGHfVSCPullRequest
=
'
ghfvs-pr-owner-number
'
;
const
BranchCapture
=
/branch
\.(
.+
)\.
ghfvsc-pr/
;
const
PullRequestRemoteMetadataKey
=
'
github-pr-remote
'
;
const
PullRequestMetadataKey
=
'
github-pr-owner-number
'
;
const
PullRequestBranchRegex
=
/branch
\.(
.+
)\.
github-pr-owner-number/
;
export
class
PullRequestGitHelper
{
static
async
checkout
(
repository
:
Repository
,
pullRequest
:
PullRequestModel
,
localBranchName
:
string
)
{
static
async
createAndCheckout
(
repository
:
Repository
,
pullRequest
:
PullRequestModel
)
{
let
localBranchName
=
await
PullRequestGitHelper
.
getBranchNameForPullRequest
(
repository
,
pullRequest
);
let
existing
=
await
repository
.
getBranch
(
localBranchName
);
if
(
existing
)
{
// already exist
await
repository
.
checkout
(
localBranchName
);
}
else
if
(
repository
.
cloneUrl
.
equals
(
pullRequest
.
head
.
repositoryCloneUrl
))
{
// branch from the same repository
await
repository
.
fetch
(
'
origin
'
,
localBranchName
);
await
repository
.
checkout
(
localBranchName
);
}
else
{
//
nothing matches
let
refSpec
=
`
${
pullRequest
.
head
.
ref
}
:
${
localBranchName
}
`
;
//
the branch is from a fork
// create remote for this fork
let
remoteName
=
await
PullRequestGitHelper
.
createRemote
(
repository
,
pullRequest
.
head
.
repositoryCloneUrl
);
await
repository
.
fetch
(
remoteName
,
refSpec
);
// fetch the branch
let
ref
=
`
${
pullRequest
.
head
.
ref
}
:
${
localBranchName
}
`
;
await
repository
.
fetch
(
remoteName
,
ref
);
await
repository
.
checkout
(
localBranchName
);
// set remote tracking branch for the local branch
await
repository
.
setTrackingBranch
(
localBranchName
,
`refs/remotes/
${
remoteName
}
/
${
pullRequest
.
head
.
ref
}
`
);
}
var
prConfigKey
=
`branch.
${
localBranchName
}
.
${
SettingGHfVSCPullRequest
}
`
;
await
repository
.
setConfig
(
prConfigKey
,
PullRequestGitHelper
.
build
GHfVSConfigKeyValue
(
pullRequest
));
let
prConfigKey
=
`branch.
${
localBranchName
}
.
${
PullRequestMetadataKey
}
`
;
await
repository
.
setConfig
(
prConfigKey
,
PullRequestGitHelper
.
build
PullRequestMetadata
(
pullRequest
));
}
static
async
getLocalBranchesForPullRequest
(
repository
:
Repository
,
pullRequest
:
PullRequestModel
):
Promise
<
string
[]
>
{
if
(
PullRequestGitHelper
.
isPullRequestFromRepository
(
repository
,
pullRequest
))
{
return
[
pullRequest
.
head
.
ref
];
}
else
{
let
key
=
PullRequestGitHelper
.
buildGHfVSConfigKeyValue
(
pullRequest
);
static
async
checkout
(
repository
:
Repository
,
remote
:
Remote
,
branchName
:
string
,
pullRequest
:
PullRequestModel
):
Promise
<
void
>
{
let
remoteName
=
remote
.
remoteName
;
await
repository
.
fetch
(
remoteName
);
let
branch
=
await
repository
.
getBranch
(
branchName
);
let
configs
=
await
repository
.
getConfigs
();
return
configs
.
map
(
config
=>
{
let
matches
=
BranchCapture
.
exec
(
config
.
key
);
if
(
matches
&&
matches
.
length
)
{
return
{
branch
:
matches
[
1
],
value
:
config
.
value
};
}
else
{
return
{
branch
:
null
,
value
:
config
.
value
};
}
}).
filter
(
c
=>
c
.
branch
&&
c
.
value
===
key
).
map
(
c
=>
c
.
value
);
if
(
!
branch
)
{
await
PullRequestGitHelper
.
fetchAndCreateBranch
(
repository
,
remote
,
branchName
,
pullRequest
);
}
}
static
async
switchToBranch
(
repository
:
Repository
,
pullRequest
:
PullRequestModel
):
Promise
<
void
>
{
let
matchingBranches
=
await
PullRequestGitHelper
.
getLocalBranchesForPullRequest
(
repository
,
pullRequest
);
if
(
matchingBranches
&&
matchingBranches
.
length
)
{
let
branchName
=
matchingBranches
[
0
];
let
remoteName
=
repository
.
HEAD
.
upstream
.
remote
;
await
repository
.
checkout
(
branchName
);
await
PullRequestGitHelper
.
markBranchAsPullRequest
(
repository
,
pullRequest
,
branchName
);
}
if
(
!
remoteName
)
{
return
;
}
static
async
getBranchForPullRequestFromExistingRemotes
(
repository
:
Repository
,
pullRequest
:
PullRequestModel
)
{
let
headRemote
=
PullRequestGitHelper
.
getHeadRemoteForPullRequest
(
repository
,
pullRequest
);
if
(
headRemote
)
{
// the head of the PR is in this repository (not fork), we can just fetch
return
{
remote
:
headRemote
,
branch
:
pullRequest
.
head
.
ref
};
}
else
{
let
key
=
PullRequestGitHelper
.
buildPullRequestMetadata
(
pullRequest
);
let
configs
=
await
repository
.
getConfigs
();
await
repository
.
fetch
(
remoteName
,
branchName
);
let
branch
=
null
;
try
{
branch
=
await
repository
.
getBranch
(
branchName
);
}
catch
(
e
)
{
}
if
(
!
branch
)
{
const
trackedBranchName
=
`refs/remotes/
${
remoteName
}
/
${
branchName
}
`
;
const
trackedBranch
=
await
repository
.
getBranch
(
trackedBranchName
);
if
(
trackedBranch
)
{
// create branch
await
repository
.
createBranch
(
branchName
,
trackedBranch
.
commit
);
await
repository
.
setTrackingBranch
(
branchName
,
trackedBranchName
);
}
else
{
throw
new
Error
(
`Could not find branch '
${
trackedBranchName
}
'.`
)
;
let
branchInfos
=
configs
.
map
(
config
=>
{
let
matches
=
PullRequestBranchRegex
.
exec
(
config
.
key
)
;
return
{
branch
:
matches
&&
matches
.
length
?
matches
[
1
]
:
null
,
value
:
config
.
value
};
}).
filter
(
c
=>
c
.
branch
&&
c
.
value
===
key
);
if
(
branchInfos
&&
branchInfos
.
length
)
{
let
remoteName
=
await
repository
.
getConfig
(
`branch.
${
branchInfos
[
0
].
branch
}
.remote`
);
let
headRemote
=
repository
.
remotes
.
filter
(
remote
=>
remote
.
remoteName
===
remoteName
);
if
(
headRemote
&&
headRemote
.
length
)
{
return
{
remote
:
headRemote
[
0
],
branch
:
branchInfos
[
0
].
branch
}
;
}
}
await
repository
.
checkout
(
branchName
);
await
PullRequestGitHelper
.
markBranchAsPullRequest
(
repository
,
pullRequest
,
branchName
);
return
null
;
}
}
static
async
getDefaultLocalBranchName
(
repository
:
Repository
,
pullRequestNumber
:
number
,
pullRequestTitle
:
string
):
Promise
<
string
>
{
let
initial
=
'
pr/
'
+
pullRequestNumber
+
'
-
'
+
PullRequestGitHelper
.
getSafeBranchName
(
pullRequestTitle
)
;
let
current
=
initial
;
let
index
=
2
;
static
async
fetchAndCreateBranch
(
repository
:
Repository
,
remote
:
Remote
,
branchName
:
string
,
pullRequest
:
PullRequestModel
)
{
let
remoteName
=
remote
.
remoteName
;
const
trackedBranchName
=
`refs/remotes/
${
remoteName
}
/
${
branchName
}
`
;
const
trackedBranch
=
await
repository
.
getBranch
(
trackedBranchName
)
;
while
(
true
)
{
let
currentBranch
=
await
repository
.
getBranch
(
current
);
if
(
currentBranch
)
{
current
=
initial
+
'
-
'
+
index
++
;
}
else
{
break
;
}
}
return
current
.
replace
(
/-*$/g
,
''
);
}
static
async
getPullRequestForCurrentBranch
(
repository
:
Repository
)
{
let
configKey
=
`branch.
${
repository
.
HEAD
.
name
}
.
${
SettingGHfVSCPullRequest
}
`
;
let
configValue
=
await
repository
.
getConfig
(
configKey
);
return
PullRequestGitHelper
.
parseGHfVSConfigKeyValue
(
configValue
);
}
static
getSafeBranchName
(
name
:
string
):
string
{
let
before
=
name
.
replace
(
InvalidBranchCharsRegex
,
'
-
'
).
replace
(
/-*$/g
,
''
);
for
(;
;)
{
let
after
=
before
.
replace
(
'
--
'
,
'
-
'
);
if
(
after
===
before
)
{
return
before
.
toLocaleLowerCase
();
}
before
=
after
;
if
(
trackedBranch
)
{
// create branch
await
repository
.
createBranch
(
branchName
,
trackedBranch
.
commit
);
await
repository
.
setTrackingBranch
(
branchName
,
trackedBranchName
);
}
else
{
throw
new
Error
(
`Could not find branch '
${
trackedBranchName
}
'.`
);
}
}
static
build
GHfVSConfigKeyValue
(
pullRequest
:
PullRequestModel
)
{
static
build
PullRequestMetadata
(
pullRequest
:
PullRequestModel
)
{
return
pullRequest
.
base
.
repositoryCloneUrl
.
owner
+
'
#
'
+
pullRequest
.
prNumber
;
}
static
parseGHfVSConfigKeyValue
(
value
:
string
)
{
static
parsePullRequestMetadata
(
value
:
string
)
{
if
(
value
)
{
let
separator
=
value
.
indexOf
(
'
#
'
);
if
(
separator
!==
-
1
)
{
...
...
@@ -158,23 +125,29 @@ export class PullRequestGitHelper {
return
null
;
}
static
async
createRemote
(
repository
:
Repository
,
cloneUrl
:
UriString
)
{
static
async
getMatchingPullRequestMetadataForBranch
(
repository
:
Repository
,
branchName
:
string
)
{
let
configKey
=
`branch.
${
branchName
}
.
${
PullRequestMetadataKey
}
`
;
let
configValue
=
await
repository
.
getConfig
(
configKey
);
return
PullRequestGitHelper
.
parsePullRequestMetadata
(
configValue
);
}
static
async
createRemote
(
repository
:
Repository
,
cloneUrl
:
Protocol
)
{
let
remotes
=
repository
.
remotes
;
remotes
.
forEach
(
remote
=>
{
if
(
new
UriString
(
remote
.
url
).
equals
(
cloneUrl
))
{
return
remote
.
n
ame
;
if
(
new
Protocol
(
remote
.
url
).
equals
(
cloneUrl
))
{
return
remote
.
repositoryN
ame
;
}
});
var
remoteName
=
PullRequestGitHelper
.
create
UniqueRemoteName
(
repository
,
cloneUrl
.
owner
);
await
repository
.
addRemote
(
remoteName
,
cloneUrl
.
toRepositoryUrl
().
toString
());
await
repository
.
setConfig
(
`remote.
${
remoteName
}
.
${
SettingCreatedByGHfVSC
}
`
,
'
true
'
);
let
remoteName
=
PullRequestGitHelper
.
get
UniqueRemoteName
(
repository
,
cloneUrl
.
owner
);
await
repository
.
addRemote
(
remoteName
,
cloneUrl
.
normalizeUri
().
toString
());
await
repository
.
setConfig
(
`remote.
${
remoteName
}
.
${
PullRequestRemoteMetadataKey
}
`
,
'
true
'
);
return
remoteName
;
}
static
async
isRemoteCreatedForPullRequest
(
repository
:
Repository
,
remoteName
:
string
)
{
let
isForPR
=
await
repository
.
getConfig
(
`remote.
${
remoteName
}
.
${
SettingCreatedByGHfVSC
}
`
);
let
isForPR
=
await
repository
.
getConfig
(
`remote.
${
remoteName
}
.
${
PullRequestRemoteMetadataKey
}
`
);
if
(
isForPR
===
'
true
'
)
{
return
true
;
...
...
@@ -183,33 +156,50 @@ export class PullRequestGitHelper {
}
}
static
createUniqueRemoteName
(
repository
:
Repository
,
name
:
string
)
{
{
var
uniqueName
=
n
ame
;
var
number
=
1
;
static
async
getBranchNameForPullRequest
(
repository
:
Repository
,
pullRequest
:
PullRequestModel
):
Promise
<
string
>
{
let
branchName
=
`pr/
${
pullRequest
.
author
.
login
}
/
${
pullRequest
.
prNumber
}
`
;
let
result
=
branchN
ame
;
let
number
=
1
;
while
(
repository
.
remotes
.
find
(
e
=>
e
.
remoteName
===
uniqueName
))
{
uniqueName
=
name
+
number
++
;
}
while
(
true
)
{
let
currentBranch
=
await
repository
.
getBranch
(
result
);
return
uniqueName
;
if
(
currentBranch
)
{
result
=
branchName
+
'
-
'
+
number
++
;
}
else
{
break
;
}
}
return
result
;
}
static
isPullRequestFromRepository
(
repository
:
Repository
,
pullRequest
:
PullRequestModel
):
boolean
{
return
repository
.
cloneUrl
&&
repository
.
cloneUrl
.
equals
(
pullRequest
.
head
.
repositoryCloneUrl
);
static
getUniqueRemoteName
(
repository
:
Repository
,
name
:
string
)
{
let
uniqueName
=
name
;
let
number
=
1
;
while
(
repository
.
remotes
.
find
(
e
=>
e
.
remoteName
===
uniqueName
))
{
uniqueName
=
name
+
number
++
;
}
return
uniqueName
;
}
static
async
getPullRequestForBranch
(
repository
:
Repository
,
branchName
:
string
)
{
let
prConfigKey
=
`branch.
${
branchName
}
.
${
SettingGHfVSCPullRequest
}
`
;
let
info
=
await
repository
.
getConfig
(
prConfigKey
);
static
getHeadRemoteForPullRequest
(
repository
:
Repository
,
pullRequest
:
PullRequestModel
):
Remote
{
let
repos
=
repository
.
githubRepositories
;
for
(
let
i
=
0
;
i
<
repos
.
length
;
i
++
)
{
let
remote
=
repos
[
i
].
remote
;
if
(
remote
.
gitProtocol
&&
remote
.
gitProtocol
.
equals
(
pullRequest
.
head
.
repositoryCloneUrl
))
{
return
remote
;
}
}
return
info
;
return
null
;
}
static
async
markBranchAsPullRequest
(
repository
:
Repository
,
pullRequest
:
PullRequestModel
,
branchName
:
string
)
{
let
prConfigKey
=
`branch.
${
branchName
}
.
${
SettingGHfVSCPullRequest
}
`
;
await
repository
.
setConfig
(
prConfigKey
,
PullRequestGitHelper
.
build
GHfVSConfigKeyValue
(
pullRequest
));
let
prConfigKey
=
`branch.
${
branchName
}
.
${
PullRequestMetadataKey
}
`
;
await
repository
.
setConfig
(
prConfigKey
,
PullRequestGitHelper
.
build
PullRequestMetadata
(
pullRequest
));
}
static
async
getLocalBranchesMarkedAsPullRequest
(
repository
:
Repository
)
{
...
...
@@ -217,9 +207,9 @@ export class PullRequestGitHelper {
let
ret
=
[];
for
(
let
i
=
0
;
i
<
branches
.
length
;
i
++
)
{
let
localInfo
=
await
PullRequestGitHelper
.
getPullRequest
ForBranch
(
repository
,
branches
[
i
]);
if
(
localInfo
)
{
ret
.
push
(
PullRequestGitHelper
.
parseGHfVSConfigKeyValue
(
localInfo
)
);
let
matchingPRMetadata
=
await
PullRequestGitHelper
.
getMatchingPullRequestMetadata
ForBranch
(
repository
,
branches
[
i
]);
if
(
matchingPRMetadata
)
{
ret
.
push
(
matchingPRMetadata
);
}
}
...
...
extensions/git-extended/src/common/remote.ts
已删除
100644 → 0
浏览文件 @
d1ddcb49
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/* --------------------------------------------------------------------------------------------
* Includes code from github/desktop, obtained from
* https://github.com/desktop/desktop/blob/master/app/src/lib/git/remote.ts
* ------------------------------------------------------------------------------------------ */
import
{
GitProcess
}
from
'
dugite
'
;
import
{
Remote
}
from
'
./models/remote
'
;
export
async
function
getRemotes
(
path
:
string
)
{
const
result
=
await
GitProcess
.
exec
([
'
remote
'
,
'
-v
'
],
path
);
const
output
=
result
.
stdout
;
const
lines
=
output
.
split
(
'
\n
'
);
const
remotes
=
lines
.
filter
(
x
=>
x
.
endsWith
(
'
(fetch)
'
))
.
map
(
x
=>
x
.
split
(
/
\s
+/
))
.
map
(
x
=>
({
name
:
x
[
0
],
url
:
x
[
1
]
}));
return
remotes
;
}
/** Parse the remote information from URL. */
export
function
parseRemote
(
remoteName
:
string
,
url
:
string
):
Remote
|
null
{
// Examples:
// https://github.com/octocat/Hello-World.git
// https://github.com/octocat/Hello-World.git/
// git@github.com:octocat/Hello-World.git
// git:github.com/octocat/Hello-World.git
const
regexes
=
[
new
RegExp
(
'
^https?://(?:.+@)?(.+)/(.+)/(.+?)(?:/|.git/?)?$
'
),
new
RegExp
(
'
^git@(.+):(.+)/(.+?)(?:/|.git)?$
'
),
new
RegExp
(
'
^git:(.+)/(.+)/(.+?)(?:/|.git)?$
'
),
new
RegExp
(
'
^ssh://git@(.+)/(.+)/(.+?)(?:/|.git)?$
'
)
];
for
(
const
regex
of
regexes
)
{
const
result
=
url
.
match
(
regex
);
if
(
!
result
)
{
continue
;
}
const
hostname
=
result
[
1
];
const
owner
=
result
[
2
];
const
name
=
result
[
3
];
if
(
hostname
)
{
return
new
Remote
(
remoteName
,
url
,
hostname
,
owner
,
name
);
}
}
return
null
;
}
extensions/git-extended/src/credentials.ts
浏览文件 @
d298248b
...
...
@@ -21,7 +21,7 @@ export class CredentialStore {
return
this
.
octokits
[
remote
.
url
];
}
if
(
this
.
configuration
.
host
===
remote
.
host
name
&&
this
.
configuration
.
accessToken
)
{
if
(
this
.
configuration
.
host
===
remote
.
host
&&
this
.
configuration
.
accessToken
)
{
this
.
octokits
[
remote
.
url
]
=
Octokit
({});
this
.
octokits
[
remote
.
url
].
authenticate
({
type
:
'
token
'
,
...
...
extensions/git-extended/src/prView/prProvider.ts
浏览文件 @
d298248b
...
...
@@ -285,7 +285,7 @@ export class PRProvider implements vscode.TreeDataProvider<PRGroupTreeItem | Pul
async
getComments
(
element
:
PullRequestModel
):
Promise
<
Comment
[]
>
{
const
reviewData
=
await
element
.
otcokit
.
pullRequests
.
getComments
({
owner
:
element
.
remote
.
owner
,
repo
:
element
.
remote
.
n
ame
,
repo
:
element
.
remote
.
repositoryN
ame
,
number
:
element
.
prItem
.
number
,
per_page
:
100
,
});
...
...
extensions/git-extended/src/review/reviewManager.ts
浏览文件 @
d298248b
...
...
@@ -113,14 +113,14 @@ export class ReviewManager implements vscode.DecorationProvider {
}
private
async
validateState
()
{
let
localInfo
=
await
PullRequestGitHelper
.
getPullRequestForCurrentBranch
(
this
.
_repository
);
let
matchingPullRequestMetadata
=
await
PullRequestGitHelper
.
getMatchingPullRequestMetadataForBranch
(
this
.
_repository
,
this
.
_repository
.
HEAD
.
name
);
if
(
!
localInfo
)
{
if
(
!
matchingPullRequestMetadata
)
{
this
.
clear
(
true
);
return
;
}
if
(
this
.
_prNumber
===
localInfo
.
prNumber
)
{
if
(
this
.
_prNumber
===
matchingPullRequestMetadata
.
prNumber
)
{
return
;
}
...
...
@@ -138,9 +138,11 @@ export class ReviewManager implements vscode.DecorationProvider {
// we switch to another PR, let's clean up first.
this
.
clear
(
false
);
this
.
_prNumber
=
localInfo
.
prNumber
;
this
.
_prNumber
=
matchingPullRequestMetadata
.
prNumber
;
this
.
_lastCommitSha
=
null
;
let
githubRepo
=
this
.
_repository
.
githubRepositories
.
find
(
repo
=>
repo
.
remote
.
owner
.
toLocaleLowerCase
()
===
localInfo
.
owner
.
toLocaleLowerCase
());
let
githubRepo
=
this
.
_repository
.
githubRepositories
.
find
(
repo
=>
repo
.
remote
.
owner
.
toLocaleLowerCase
()
===
matchingPullRequestMetadata
.
owner
.
toLocaleLowerCase
()
);
if
(
!
githubRepo
)
{
return
;
// todo, should show warning
...
...
@@ -487,14 +489,12 @@ export class ReviewManager implements vscode.DecorationProvider {
this
.
statusBarItem
.
show
();
try
{
// todo, check if HEAD is dirty
let
localBranches
=
await
PullRequestGitHelper
.
getLocalBranchesForPullRequest
(
this
.
_repository
,
pr
);
let
localBranchInfo
=
await
PullRequestGitHelper
.
getBranchForPullRequestFromExistingRemotes
(
this
.
_repository
,
pr
);
if
(
localBranch
es
.
length
>
0
)
{
await
PullRequestGitHelper
.
switchToBranch
(
this
.
_repository
,
pr
);
if
(
localBranch
Info
)
{
await
PullRequestGitHelper
.
checkout
(
this
.
_repository
,
localBranchInfo
.
remote
,
localBranchInfo
.
branch
,
pr
);
}
else
{
let
branchName
=
await
PullRequestGitHelper
.
getDefaultLocalBranchName
(
this
.
_repository
,
pr
.
prNumber
,
pr
.
title
);
await
PullRequestGitHelper
.
checkout
(
this
.
_repository
,
pr
,
branchName
);
await
PullRequestGitHelper
.
createAndCheckout
(
this
.
_repository
,
pr
);
}
}
catch
(
e
)
{
if
(
e
.
gitErrorCode
)
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录