mirror of
https://github.com/gogs/gogs.git
synced 2025-12-20 15:20:01 +01:00
git: migrate to github.com/gogs/git-module@v1.0.0 (#5958)
* WIP * Finish `internal/db/git_diff.go` * FInish internal/db/mirror.go * Finish internal/db/pull.go * Finish internal/db/release.go * Finish internal/db/repo.go * Finish internal/db/repo_branch.go * Finish internal/db/repo_editor.go * Finish internal/db/update.go * Save my work * Add license header * Compile! * Merge master * Finish internal/cmd/hook.go * Finish internal/conf/static.go * Finish internal/context/repo.go * Finish internal/db/action.go * Finish internal/db/git_diff.go * Fix submodule URL inferring * Finish internal/db/mirror.go * Updat to beta.4 * css: update fonts * Finish internal/db/pull.go * Finish internal/db/release.go * Finish internal/db/repo_branch.go * Finish internal/db/wiki.go * gitutil: enhance infer submodule UR * Finish internal/route/api/v1/repo/commits.go * mirror: only collect branch commits after sync * mirror: fix tag support * Finish internal/db/repo.go * Finish internal/db/repo_editor.go * Finish internal/db/update.go * Finish internal/gitutil/pull_request.go * Make it compile * Finish internal/route/repo/setting.go * Finish internal/route/repo/branch.go * Finish internal/route/api/v1/repo/file.go * Finish internal/route/repo/download.go * Finish internal/route/repo/editor.go * Use helper * Finish internal/route/repo/issue.go * Finish internal/route/repo/pull.go * Finish internal/route/repo/release.go * Finish internal/route/repo/repo.go * Finish internal/route/repo/wiki.go * Finish internal/route/repo/commit.go * Finish internal/route/repo/view.go * Finish internal/gitutil/tag.go * go.sum
This commit is contained in:
@@ -424,12 +424,12 @@ OLDER_THAN = 24h
|
|||||||
[git]
|
[git]
|
||||||
; Disables highlight of added and removed changes
|
; Disables highlight of added and removed changes
|
||||||
DISABLE_DIFF_HIGHLIGHT = false
|
DISABLE_DIFF_HIGHLIGHT = false
|
||||||
|
; Max number of files shown in diff view
|
||||||
|
MAX_GIT_DIFF_FILES = 100
|
||||||
; Max number of lines allowed of a single file in diff view
|
; Max number of lines allowed of a single file in diff view
|
||||||
MAX_GIT_DIFF_LINES = 1000
|
MAX_GIT_DIFF_LINES = 1000
|
||||||
; Max number of characters of a line allowed in diff view
|
; Max number of characters of a line allowed in diff view
|
||||||
MAX_GIT_DIFF_LINE_CHARACTERS = 500
|
MAX_GIT_DIFF_LINE_CHARACTERS = 2000
|
||||||
; Max number of files shown in diff view
|
|
||||||
MAX_GIT_DIFF_FILES = 100
|
|
||||||
; Arguments for command 'git gc', e.g. "--aggressive --auto"
|
; Arguments for command 'git gc', e.g. "--aggressive --auto"
|
||||||
; see more on http://git-scm.com/docs/git-gc/1.7.5
|
; see more on http://git-scm.com/docs/git-gc/1.7.5
|
||||||
GC_ARGS =
|
GC_ARGS =
|
||||||
|
|||||||
7
go.mod
7
go.mod
@@ -5,7 +5,7 @@ go 1.12
|
|||||||
require (
|
require (
|
||||||
github.com/bgentry/speakeasy v0.1.0 // indirect
|
github.com/bgentry/speakeasy v0.1.0 // indirect
|
||||||
github.com/denisenkom/go-mssqldb v0.0.0-20191001013358-cfbb681360f0
|
github.com/denisenkom/go-mssqldb v0.0.0-20191001013358-cfbb681360f0
|
||||||
github.com/editorconfig/editorconfig-core-go/v2 v2.2.1
|
github.com/editorconfig/editorconfig-core-go/v2 v2.3.0
|
||||||
github.com/fatih/color v1.9.0 // indirect
|
github.com/fatih/color v1.9.0 // indirect
|
||||||
github.com/go-macaron/binding v1.0.1
|
github.com/go-macaron/binding v1.0.1
|
||||||
github.com/go-macaron/cache v0.0.0-20190810181446-10f7c57e2196
|
github.com/go-macaron/cache v0.0.0-20190810181446-10f7c57e2196
|
||||||
@@ -18,10 +18,11 @@ require (
|
|||||||
github.com/go-sql-driver/mysql v1.4.1
|
github.com/go-sql-driver/mysql v1.4.1
|
||||||
github.com/gogs/chardet v0.0.0-20150115103509-2404f7772561
|
github.com/gogs/chardet v0.0.0-20150115103509-2404f7772561
|
||||||
github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14
|
github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14
|
||||||
github.com/gogs/git-module v0.8.3
|
github.com/gogs/git-module v1.0.0
|
||||||
github.com/gogs/go-gogs-client v0.0.0-20200128182646-c69cb7680fd4
|
github.com/gogs/go-gogs-client v0.0.0-20200128182646-c69cb7680fd4
|
||||||
github.com/gogs/go-libravatar v0.0.0-20191106065024-33a75213d0a0
|
github.com/gogs/go-libravatar v0.0.0-20191106065024-33a75213d0a0
|
||||||
github.com/gogs/minwinsvc v0.0.0-20170301035411-95be6356811a
|
github.com/gogs/minwinsvc v0.0.0-20170301035411-95be6356811a
|
||||||
|
github.com/google/go-cmp v0.3.0
|
||||||
github.com/google/go-github v17.0.0+incompatible
|
github.com/google/go-github v17.0.0+incompatible
|
||||||
github.com/google/go-querystring v1.0.0 // indirect
|
github.com/google/go-querystring v1.0.0 // indirect
|
||||||
github.com/issue9/identicon v1.0.1
|
github.com/issue9/identicon v1.0.1
|
||||||
@@ -61,7 +62,7 @@ require (
|
|||||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||||
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect
|
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect
|
||||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
|
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
|
||||||
gopkg.in/ini.v1 v1.52.0
|
gopkg.in/ini.v1 v1.53.0
|
||||||
gopkg.in/ldap.v2 v2.5.1
|
gopkg.in/ldap.v2 v2.5.1
|
||||||
gopkg.in/macaron.v1 v1.3.4
|
gopkg.in/macaron.v1 v1.3.4
|
||||||
unknwon.dev/clog/v2 v2.1.2
|
unknwon.dev/clog/v2 v2.1.2
|
||||||
|
|||||||
12
go.sum
12
go.sum
@@ -41,6 +41,8 @@ github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1
|
|||||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||||
github.com/editorconfig/editorconfig-core-go/v2 v2.2.1 h1:jY5PCRQf4V0oqpim/Ympl6MwHcb9+nBHEnHOPXqNZ/A=
|
github.com/editorconfig/editorconfig-core-go/v2 v2.2.1 h1:jY5PCRQf4V0oqpim/Ympl6MwHcb9+nBHEnHOPXqNZ/A=
|
||||||
github.com/editorconfig/editorconfig-core-go/v2 v2.2.1/go.mod h1:6XDmqAZsQu8ikS+onLRJfLZvTP3RWTVT8ROX6qcdkio=
|
github.com/editorconfig/editorconfig-core-go/v2 v2.2.1/go.mod h1:6XDmqAZsQu8ikS+onLRJfLZvTP3RWTVT8ROX6qcdkio=
|
||||||
|
github.com/editorconfig/editorconfig-core-go/v2 v2.3.0 h1:QD1YB/rbntMEQIKM42kQOaqGdS13UvGsl9c8m/nFNWY=
|
||||||
|
github.com/editorconfig/editorconfig-core-go/v2 v2.3.0/go.mod h1:RNdPfKd9PliYEUZ3r+GxbDsSHNnEluC1wdkQJc3jD4k=
|
||||||
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
||||||
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
||||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
@@ -82,6 +84,10 @@ github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14 h1:yXtpJr/LV6PFu4nTLgfjQ
|
|||||||
github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14/go.mod h1:jPoNZLWDAqA5N3G5amEoiNbhVrmM+ZQEcnQvNQ2KaZk=
|
github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14/go.mod h1:jPoNZLWDAqA5N3G5amEoiNbhVrmM+ZQEcnQvNQ2KaZk=
|
||||||
github.com/gogs/git-module v0.8.3 h1:9f8oxSs9OACWrGBYMVnnQNzyTcVN+zzcBM7CXnbmezw=
|
github.com/gogs/git-module v0.8.3 h1:9f8oxSs9OACWrGBYMVnnQNzyTcVN+zzcBM7CXnbmezw=
|
||||||
github.com/gogs/git-module v0.8.3/go.mod h1:aj4tcm7DxaszJWpZLZIRL6gfPXyguAHiE1PDfAAPrCw=
|
github.com/gogs/git-module v0.8.3/go.mod h1:aj4tcm7DxaszJWpZLZIRL6gfPXyguAHiE1PDfAAPrCw=
|
||||||
|
github.com/gogs/git-module v1.0.0-beta.4 h1:5CyCvTfrb2n5LRpHcNIaFnywHDkM/NxSZVP6t4tpTXI=
|
||||||
|
github.com/gogs/git-module v1.0.0-beta.4/go.mod h1:oN37FFStFjdnTJXsSbhIHKJXh2YeDsEcXPATVz/oeuQ=
|
||||||
|
github.com/gogs/git-module v1.0.0 h1:iOlCZ5kPc3RjnWRxdziL5hjCaosYyZw/Lf2odzR/kjw=
|
||||||
|
github.com/gogs/git-module v1.0.0/go.mod h1:oN37FFStFjdnTJXsSbhIHKJXh2YeDsEcXPATVz/oeuQ=
|
||||||
github.com/gogs/go-gogs-client v0.0.0-20200128182646-c69cb7680fd4 h1:C7NryI/RQhsIWwC2bHN601P1wJKeuQ6U/UCOYTn3Cic=
|
github.com/gogs/go-gogs-client v0.0.0-20200128182646-c69cb7680fd4 h1:C7NryI/RQhsIWwC2bHN601P1wJKeuQ6U/UCOYTn3Cic=
|
||||||
github.com/gogs/go-gogs-client v0.0.0-20200128182646-c69cb7680fd4/go.mod h1:fR6z1Ie6rtF7kl/vBYMfgD5/G5B1blui7z426/sj2DU=
|
github.com/gogs/go-gogs-client v0.0.0-20200128182646-c69cb7680fd4/go.mod h1:fR6z1Ie6rtF7kl/vBYMfgD5/G5B1blui7z426/sj2DU=
|
||||||
github.com/gogs/go-libravatar v0.0.0-20191106065024-33a75213d0a0 h1:K02vod+sn3M1OOkdqi2tPxN2+xESK4qyITVQ3JkGEv4=
|
github.com/gogs/go-libravatar v0.0.0-20191106065024-33a75213d0a0 h1:K02vod+sn3M1OOkdqi2tPxN2+xESK4qyITVQ3JkGEv4=
|
||||||
@@ -305,6 +311,7 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@@ -363,8 +370,11 @@ gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AW
|
|||||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
|
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
|
||||||
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
gopkg.in/ini.v1 v1.46.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.46.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
gopkg.in/ini.v1 v1.52.0 h1:j+Lt/M1oPPejkniCg1TkWE2J3Eh1oZTsHSXzMTzUXn4=
|
gopkg.in/ini.v1 v1.52.0 h1:j+Lt/M1oPPejkniCg1TkWE2J3Eh1oZTsHSXzMTzUXn4=
|
||||||
gopkg.in/ini.v1 v1.52.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.52.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
gopkg.in/ini.v1 v1.53.0 h1:c7ruDvTQi0MUTFuNpDRXLSjs7xT4TerM1icIg4uKWRg=
|
||||||
|
gopkg.in/ini.v1 v1.53.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
gopkg.in/ldap.v2 v2.5.1 h1:wiu0okdNfjlBzg6UWvd1Hn8Y+Ux17/u/4nlk4CQr6tU=
|
gopkg.in/ldap.v2 v2.5.1 h1:wiu0okdNfjlBzg6UWvd1Hn8Y+Ux17/u/4nlk4CQr6tU=
|
||||||
gopkg.in/ldap.v2 v2.5.1/go.mod h1:oI0cpe/D7HRtBQl8aTg+ZmzFUAvu4lsv3eLXMLGFxWk=
|
gopkg.in/ldap.v2 v2.5.1/go.mod h1:oI0cpe/D7HRtBQl8aTg+ZmzFUAvu4lsv3eLXMLGFxWk=
|
||||||
gopkg.in/macaron.v1 v1.3.4 h1:HvIscOwxhFhx3swWM/979wh2QMYyuXrNmrF9l+j3HZs=
|
gopkg.in/macaron.v1 v1.3.4 h1:HvIscOwxhFhx3swWM/979wh2QMYyuXrNmrF9l+j3HZs=
|
||||||
@@ -375,6 +385,8 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD
|
|||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
|
||||||
|
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -9,6 +9,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -25,7 +26,6 @@ import (
|
|||||||
"gogs.io/gogs/internal/db/errors"
|
"gogs.io/gogs/internal/db/errors"
|
||||||
"gogs.io/gogs/internal/email"
|
"gogs.io/gogs/internal/email"
|
||||||
"gogs.io/gogs/internal/httplib"
|
"gogs.io/gogs/internal/httplib"
|
||||||
"gogs.io/gogs/internal/template"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -87,7 +87,7 @@ func runHookPreReceive(c *cli.Context) error {
|
|||||||
}
|
}
|
||||||
oldCommitID := string(fields[0])
|
oldCommitID := string(fields[0])
|
||||||
newCommitID := string(fields[1])
|
newCommitID := string(fields[1])
|
||||||
branchName := strings.TrimPrefix(string(fields[2]), git.BRANCH_PREFIX)
|
branchName := git.RefShortName(string(fields[2]))
|
||||||
|
|
||||||
// Branch protection
|
// Branch protection
|
||||||
repoID := com.StrTo(os.Getenv(db.ENV_REPO_ID)).MustInt64()
|
repoID := com.StrTo(os.Getenv(db.ENV_REPO_ID)).MustInt64()
|
||||||
@@ -121,7 +121,7 @@ func runHookPreReceive(c *cli.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check and deletion
|
// check and deletion
|
||||||
if newCommitID == git.EMPTY_SHA {
|
if newCommitID == git.EmptyID {
|
||||||
fail(fmt.Sprintf("Branch '%s' is protected from deletion", branchName), "")
|
fail(fmt.Sprintf("Branch '%s' is protected from deletion", branchName), "")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,7 +221,7 @@ func runHookPostReceive(c *cli.Context) error {
|
|||||||
options := db.PushUpdateOptions{
|
options := db.PushUpdateOptions{
|
||||||
OldCommitID: string(fields[0]),
|
OldCommitID: string(fields[0]),
|
||||||
NewCommitID: string(fields[1]),
|
NewCommitID: string(fields[1]),
|
||||||
RefFullName: string(fields[2]),
|
FullRefspec: string(fields[2]),
|
||||||
PusherID: com.StrTo(os.Getenv(db.ENV_AUTH_USER_ID)).MustInt64(),
|
PusherID: com.StrTo(os.Getenv(db.ENV_AUTH_USER_ID)).MustInt64(),
|
||||||
PusherName: os.Getenv(db.ENV_AUTH_USER_NAME),
|
PusherName: os.Getenv(db.ENV_AUTH_USER_NAME),
|
||||||
RepoUserName: os.Getenv(db.ENV_REPO_OWNER_NAME),
|
RepoUserName: os.Getenv(db.ENV_REPO_OWNER_NAME),
|
||||||
@@ -232,19 +232,20 @@ func runHookPostReceive(c *cli.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Ask for running deliver hook and test pull request tasks
|
// Ask for running deliver hook and test pull request tasks
|
||||||
reqURL := conf.Server.LocalRootURL + options.RepoUserName + "/" + options.RepoName + "/tasks/trigger?branch=" +
|
q := make(url.Values)
|
||||||
template.EscapePound(strings.TrimPrefix(options.RefFullName, git.BRANCH_PREFIX)) +
|
q.Add("branch", git.RefShortName(options.FullRefspec))
|
||||||
"&secret=" + os.Getenv(db.ENV_REPO_OWNER_SALT_MD5) +
|
q.Add("secret", os.Getenv(db.ENV_REPO_OWNER_SALT_MD5))
|
||||||
"&pusher=" + os.Getenv(db.ENV_AUTH_USER_ID)
|
q.Add("pusher", os.Getenv(db.ENV_AUTH_USER_ID))
|
||||||
|
reqURL := fmt.Sprintf("%s%s/%s/tasks/trigger?%s", conf.Server.LocalRootURL, options.RepoUserName, options.RepoName, q.Encode())
|
||||||
log.Trace("Trigger task: %s", reqURL)
|
log.Trace("Trigger task: %s", reqURL)
|
||||||
|
|
||||||
resp, err := httplib.Head(reqURL).SetTLSClientConfig(&tls.Config{
|
resp, err := httplib.Head(reqURL).SetTLSClientConfig(&tls.Config{
|
||||||
InsecureSkipVerify: true,
|
InsecureSkipVerify: true,
|
||||||
}).Response()
|
}).Response()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
resp.Body.Close()
|
_ = resp.Body.Close()
|
||||||
if resp.StatusCode/100 != 2 {
|
if resp.StatusCode/100 != 2 {
|
||||||
log.Error("Failed to trigger task: not 2xx response code")
|
log.Error("Failed to trigger task: unsuccessful response code %d", resp.StatusCode)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Error("Failed to trigger task: %v", err)
|
log.Error("Failed to trigger task: %v", err)
|
||||||
|
|||||||
@@ -352,9 +352,9 @@ var (
|
|||||||
Version string `ini:"-"`
|
Version string `ini:"-"`
|
||||||
|
|
||||||
DisableDiffHighlight bool
|
DisableDiffHighlight bool
|
||||||
MaxGitDiffLines int
|
MaxDiffFiles int `ini:"MAX_GIT_DIFF_FILES"`
|
||||||
MaxGitDiffLineCharacters int
|
MaxDiffLines int `ini:"MAX_GIT_DIFF_LINES"`
|
||||||
MaxGitDiffFiles int
|
MaxDiffLineChars int `ini:"MAX_GIT_DIFF_LINE_CHARACTERS"`
|
||||||
GCArgs []string `ini:"GC_ARGS" delim:" "`
|
GCArgs []string `ini:"GC_ARGS" delim:" "`
|
||||||
Timeout struct {
|
Timeout struct {
|
||||||
Migrate int
|
Migrate int
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ func (c *Context) Handle(status int, msg string, err error) {
|
|||||||
c.Data["Title"] = "Page Not Found"
|
c.Data["Title"] = "Page Not Found"
|
||||||
case http.StatusInternalServerError:
|
case http.StatusInternalServerError:
|
||||||
c.Data["Title"] = "Internal Server Error"
|
c.Data["Title"] = "Internal Server Error"
|
||||||
log.Error("%s: %v", msg, err)
|
log.ErrorDepth(5, "%s: %v", msg, err)
|
||||||
if !conf.IsProdMode() || (c.IsLogged && c.User.IsAdmin) {
|
if !conf.IsProdMode() || (c.IsLogged && c.User.IsAdmin) {
|
||||||
c.Data["ErrorMsg"] = err
|
c.Data["ErrorMsg"] = err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,19 +5,20 @@
|
|||||||
package context
|
package context
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/editorconfig/editorconfig-core-go/v2"
|
"github.com/editorconfig/editorconfig-core-go/v2"
|
||||||
|
"github.com/pkg/errors"
|
||||||
"gopkg.in/macaron.v1"
|
"gopkg.in/macaron.v1"
|
||||||
|
|
||||||
"github.com/gogs/git-module"
|
"github.com/gogs/git-module"
|
||||||
|
|
||||||
"gogs.io/gogs/internal/conf"
|
"gogs.io/gogs/internal/conf"
|
||||||
"gogs.io/gogs/internal/db"
|
"gogs.io/gogs/internal/db"
|
||||||
"gogs.io/gogs/internal/db/errors"
|
dberrors "gogs.io/gogs/internal/db/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PullRequest struct {
|
type PullRequest struct {
|
||||||
@@ -75,26 +76,23 @@ func (r *Repository) CanEnableEditor() bool {
|
|||||||
return r.Repository.CanEnableEditor() && r.IsViewBranch && r.IsWriter() && !r.Repository.IsBranchRequirePullRequest(r.BranchName)
|
return r.Repository.CanEnableEditor() && r.IsViewBranch && r.IsWriter() && !r.Repository.IsBranchRequirePullRequest(r.BranchName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetEditorconfig returns the .editorconfig definition if found in the
|
// Editorconfig returns the ".editorconfig" definition if found in the HEAD of the default branch.
|
||||||
// HEAD of the default repo branch.
|
func (r *Repository) Editorconfig() (*editorconfig.Editorconfig, error) {
|
||||||
func (r *Repository) GetEditorconfig() (*editorconfig.Editorconfig, error) {
|
commit, err := r.GitRepo.BranchCommit(r.Repository.DefaultBranch)
|
||||||
commit, err := r.GitRepo.GetBranchCommit(r.Repository.DefaultBranch)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, errors.Wrapf(err, "get commit of branch %q ", r.Repository.DefaultBranch)
|
||||||
}
|
}
|
||||||
treeEntry, err := commit.GetTreeEntryByPath(".editorconfig")
|
|
||||||
|
entry, err := commit.TreeEntry(".editorconfig")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, errors.Wrap(err, "get .editorconfig")
|
||||||
}
|
}
|
||||||
reader, err := treeEntry.Blob().Data()
|
|
||||||
|
p, err := entry.Blob().Bytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, errors.Wrap(err, "read .editorconfig")
|
||||||
}
|
}
|
||||||
data, err := ioutil.ReadAll(reader)
|
return editorconfig.Parse(bytes.NewReader(p))
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return editorconfig.ParseBytes(data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeURL accepts a string or url.URL as argument and returns escaped URL prepended with repository URL.
|
// MakeURL accepts a string or url.URL as argument and returns escaped URL prepended with repository URL.
|
||||||
@@ -149,7 +147,7 @@ func RepoAssignment(pages ...bool) macaron.Handler {
|
|||||||
} else {
|
} else {
|
||||||
owner, err = db.GetUserByName(ownerName)
|
owner, err = db.GetUserByName(ownerName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.NotFoundOrServerError("GetUserByName", errors.IsUserNotExist, err)
|
c.NotFoundOrServerError("GetUserByName", dberrors.IsUserNotExist, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -158,7 +156,7 @@ func RepoAssignment(pages ...bool) macaron.Handler {
|
|||||||
|
|
||||||
repo, err := db.GetRepositoryByName(owner.ID, repoName)
|
repo, err := db.GetRepositoryByName(owner.ID, repoName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.NotFoundOrServerError("GetRepositoryByName", errors.IsRepoNotExist, err)
|
c.NotFoundOrServerError("GetRepositoryByName", dberrors.IsRepoNotExist, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,16 +220,16 @@ func RepoAssignment(pages ...bool) macaron.Handler {
|
|||||||
c.Data["Mirror"] = c.Repo.Mirror
|
c.Data["Mirror"] = c.Repo.Mirror
|
||||||
}
|
}
|
||||||
|
|
||||||
gitRepo, err := git.OpenRepository(db.RepoPath(ownerName, repoName))
|
gitRepo, err := git.Open(db.RepoPath(ownerName, repoName))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ServerError(fmt.Sprintf("RepoAssignment Invalid repo '%s'", c.Repo.Repository.RepoPath()), err)
|
c.ServerError("open repository", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.Repo.GitRepo = gitRepo
|
c.Repo.GitRepo = gitRepo
|
||||||
|
|
||||||
tags, err := c.Repo.GitRepo.GetTags()
|
tags, err := c.Repo.GitRepo.Tags()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ServerError(fmt.Sprintf("GetTags '%s'", c.Repo.Repository.RepoPath()), err)
|
c.ServerError("get tags", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.Data["Tags"] = tags
|
c.Data["Tags"] = tags
|
||||||
@@ -260,21 +258,21 @@ func RepoAssignment(pages ...bool) macaron.Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
c.Data["TagName"] = c.Repo.TagName
|
c.Data["TagName"] = c.Repo.TagName
|
||||||
brs, err := c.Repo.GitRepo.GetBranches()
|
branches, err := c.Repo.GitRepo.Branches()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ServerError("GetBranches", err)
|
c.ServerError("get branches", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.Data["Branches"] = brs
|
c.Data["Branches"] = branches
|
||||||
c.Data["BrancheCount"] = len(brs)
|
c.Data["BrancheCount"] = len(branches)
|
||||||
|
|
||||||
// If not branch selected, try default one.
|
// If not branch selected, try default one.
|
||||||
// If default branch doesn't exists, fall back to some other branch.
|
// If default branch doesn't exists, fall back to some other branch.
|
||||||
if len(c.Repo.BranchName) == 0 {
|
if len(c.Repo.BranchName) == 0 {
|
||||||
if len(c.Repo.Repository.DefaultBranch) > 0 && gitRepo.IsBranchExist(c.Repo.Repository.DefaultBranch) {
|
if len(c.Repo.Repository.DefaultBranch) > 0 && gitRepo.HasBranch(c.Repo.Repository.DefaultBranch) {
|
||||||
c.Repo.BranchName = c.Repo.Repository.DefaultBranch
|
c.Repo.BranchName = c.Repo.Repository.DefaultBranch
|
||||||
} else if len(brs) > 0 {
|
} else if len(branches) > 0 {
|
||||||
c.Repo.BranchName = brs[0]
|
c.Repo.BranchName = branches[0]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.Data["BranchName"] = c.Repo.BranchName
|
c.Data["BranchName"] = c.Repo.BranchName
|
||||||
@@ -300,7 +298,7 @@ func RepoRef() macaron.Handler {
|
|||||||
// For API calls.
|
// For API calls.
|
||||||
if c.Repo.GitRepo == nil {
|
if c.Repo.GitRepo == nil {
|
||||||
repoPath := db.RepoPath(c.Repo.Owner.Name, c.Repo.Repository.Name)
|
repoPath := db.RepoPath(c.Repo.Owner.Name, c.Repo.Repository.Name)
|
||||||
c.Repo.GitRepo, err = git.OpenRepository(repoPath)
|
c.Repo.GitRepo, err = git.Open(repoPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Handle(500, "RepoRef Invalid repo "+repoPath, err)
|
c.Handle(500, "RepoRef Invalid repo "+repoPath, err)
|
||||||
return
|
return
|
||||||
@@ -310,17 +308,17 @@ func RepoRef() macaron.Handler {
|
|||||||
// Get default branch.
|
// Get default branch.
|
||||||
if len(c.Params("*")) == 0 {
|
if len(c.Params("*")) == 0 {
|
||||||
refName = c.Repo.Repository.DefaultBranch
|
refName = c.Repo.Repository.DefaultBranch
|
||||||
if !c.Repo.GitRepo.IsBranchExist(refName) {
|
if !c.Repo.GitRepo.HasBranch(refName) {
|
||||||
brs, err := c.Repo.GitRepo.GetBranches()
|
branches, err := c.Repo.GitRepo.Branches()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Handle(500, "GetBranches", err)
|
c.ServerError("get branches", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
refName = brs[0]
|
refName = branches[0]
|
||||||
}
|
}
|
||||||
c.Repo.Commit, err = c.Repo.GitRepo.GetBranchCommit(refName)
|
c.Repo.Commit, err = c.Repo.GitRepo.BranchCommit(refName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Handle(500, "GetBranchCommit", err)
|
c.ServerError("get branch commit", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.Repo.CommitID = c.Repo.Commit.ID.String()
|
c.Repo.CommitID = c.Repo.Commit.ID.String()
|
||||||
@@ -332,8 +330,8 @@ func RepoRef() macaron.Handler {
|
|||||||
for i, part := range parts {
|
for i, part := range parts {
|
||||||
refName = strings.TrimPrefix(refName+"/"+part, "/")
|
refName = strings.TrimPrefix(refName+"/"+part, "/")
|
||||||
|
|
||||||
if c.Repo.GitRepo.IsBranchExist(refName) ||
|
if c.Repo.GitRepo.HasBranch(refName) ||
|
||||||
c.Repo.GitRepo.IsTagExist(refName) {
|
c.Repo.GitRepo.HasTag(refName) {
|
||||||
if i < len(parts)-1 {
|
if i < len(parts)-1 {
|
||||||
c.Repo.TreePath = strings.Join(parts[i+1:], "/")
|
c.Repo.TreePath = strings.Join(parts[i+1:], "/")
|
||||||
}
|
}
|
||||||
@@ -346,21 +344,21 @@ func RepoRef() macaron.Handler {
|
|||||||
c.Repo.TreePath = strings.Join(parts[1:], "/")
|
c.Repo.TreePath = strings.Join(parts[1:], "/")
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.Repo.GitRepo.IsBranchExist(refName) {
|
if c.Repo.GitRepo.HasBranch(refName) {
|
||||||
c.Repo.IsViewBranch = true
|
c.Repo.IsViewBranch = true
|
||||||
|
|
||||||
c.Repo.Commit, err = c.Repo.GitRepo.GetBranchCommit(refName)
|
c.Repo.Commit, err = c.Repo.GitRepo.BranchCommit(refName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Handle(500, "GetBranchCommit", err)
|
c.ServerError("get branch commit", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.Repo.CommitID = c.Repo.Commit.ID.String()
|
c.Repo.CommitID = c.Repo.Commit.ID.String()
|
||||||
|
|
||||||
} else if c.Repo.GitRepo.IsTagExist(refName) {
|
} else if c.Repo.GitRepo.HasTag(refName) {
|
||||||
c.Repo.IsViewTag = true
|
c.Repo.IsViewTag = true
|
||||||
c.Repo.Commit, err = c.Repo.GitRepo.GetTagCommit(refName)
|
c.Repo.Commit, err = c.Repo.GitRepo.TagCommit(refName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Handle(500, "GetTagCommit", err)
|
c.ServerError("get tag commit", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.Repo.CommitID = c.Repo.Commit.ID.String()
|
c.Repo.CommitID = c.Repo.Commit.ID.String()
|
||||||
@@ -368,7 +366,7 @@ func RepoRef() macaron.Handler {
|
|||||||
c.Repo.IsViewCommit = true
|
c.Repo.IsViewCommit = true
|
||||||
c.Repo.CommitID = refName
|
c.Repo.CommitID = refName
|
||||||
|
|
||||||
c.Repo.Commit, err = c.Repo.GitRepo.GetCommit(refName)
|
c.Repo.Commit, err = c.Repo.GitRepo.CatFileCommit(refName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.NotFound()
|
c.NotFound()
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -268,9 +268,9 @@ func (pc *PushCommits) ToApiPayloadCommits(repoPath, repoURL string) ([]*api.Pay
|
|||||||
return nil, fmt.Errorf("GetUserByEmail: %v", err)
|
return nil, fmt.Errorf("GetUserByEmail: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fileStatus, err := git.GetCommitFileStatus(repoPath, commit.Sha1)
|
nameStatus, err := git.RepoShowNameStatus(repoPath, commit.Sha1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("FileStatus [commit_sha1: %s]: %v", commit.Sha1, err)
|
return nil, fmt.Errorf("show name status [commit_sha1: %s]: %v", commit.Sha1, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
commits[i] = &api.PayloadCommit{
|
commits[i] = &api.PayloadCommit{
|
||||||
@@ -287,9 +287,9 @@ func (pc *PushCommits) ToApiPayloadCommits(repoPath, repoURL string) ([]*api.Pay
|
|||||||
Email: commit.CommitterEmail,
|
Email: commit.CommitterEmail,
|
||||||
UserName: committerUsername,
|
UserName: committerUsername,
|
||||||
},
|
},
|
||||||
Added: fileStatus.Added,
|
Added: nameStatus.Added,
|
||||||
Removed: fileStatus.Removed,
|
Removed: nameStatus.Removed,
|
||||||
Modified: fileStatus.Modified,
|
Modified: nameStatus.Modified,
|
||||||
Timestamp: commit.Timestamp,
|
Timestamp: commit.Timestamp,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -298,21 +298,21 @@ func (pc *PushCommits) ToApiPayloadCommits(repoPath, repoURL string) ([]*api.Pay
|
|||||||
|
|
||||||
// AvatarLink tries to match user in database with e-mail
|
// AvatarLink tries to match user in database with e-mail
|
||||||
// in order to show custom avatar, and falls back to general avatar link.
|
// in order to show custom avatar, and falls back to general avatar link.
|
||||||
func (push *PushCommits) AvatarLink(email string) string {
|
func (pcs *PushCommits) AvatarLink(email string) string {
|
||||||
_, ok := push.avatars[email]
|
_, ok := pcs.avatars[email]
|
||||||
if !ok {
|
if !ok {
|
||||||
u, err := GetUserByEmail(email)
|
u, err := GetUserByEmail(email)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
push.avatars[email] = tool.AvatarLink(email)
|
pcs.avatars[email] = tool.AvatarLink(email)
|
||||||
if !errors.IsUserNotExist(err) {
|
if !errors.IsUserNotExist(err) {
|
||||||
log.Error("GetUserByEmail: %v", err)
|
log.Error("GetUserByEmail: %v", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
push.avatars[email] = u.RelAvatarLink()
|
pcs.avatars[email] = u.RelAvatarLink()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return push.avatars[email]
|
return pcs.avatars[email]
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateIssuesCommit checks if issues are manipulated by commit message.
|
// UpdateIssuesCommit checks if issues are manipulated by commit message.
|
||||||
@@ -474,12 +474,12 @@ func CommitRepoAction(opts CommitRepoActionOptions) error {
|
|||||||
return fmt.Errorf("UpdateRepository: %v", err)
|
return fmt.Errorf("UpdateRepository: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
isNewRef := opts.OldCommitID == git.EMPTY_SHA
|
isNewRef := opts.OldCommitID == git.EmptyID
|
||||||
isDelRef := opts.NewCommitID == git.EMPTY_SHA
|
isDelRef := opts.NewCommitID == git.EmptyID
|
||||||
|
|
||||||
opType := ACTION_COMMIT_REPO
|
opType := ACTION_COMMIT_REPO
|
||||||
// Check if it's tag push or branch.
|
// Check if it's tag push or branch.
|
||||||
if strings.HasPrefix(opts.RefFullName, git.TAG_PREFIX) {
|
if strings.HasPrefix(opts.RefFullName, git.RefsTags) {
|
||||||
opType = ACTION_PUSH_TAG
|
opType = ACTION_PUSH_TAG
|
||||||
} else {
|
} else {
|
||||||
// if not the first commit, set the compare URL.
|
// if not the first commit, set the compare URL.
|
||||||
@@ -504,7 +504,7 @@ func CommitRepoAction(opts CommitRepoActionOptions) error {
|
|||||||
return fmt.Errorf("Marshal: %v", err)
|
return fmt.Errorf("Marshal: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
refName := git.RefEndName(opts.RefFullName)
|
refName := git.RefShortName(opts.RefFullName)
|
||||||
action := &Action{
|
action := &Action{
|
||||||
ActUserID: pusher.ID,
|
ActUserID: pusher.ID,
|
||||||
ActUserName: pusher.Name,
|
ActUserName: pusher.Name,
|
||||||
|
|||||||
@@ -1,194 +0,0 @@
|
|||||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a MIT-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package db
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"html"
|
|
||||||
"html/template"
|
|
||||||
"io"
|
|
||||||
|
|
||||||
"github.com/sergi/go-diff/diffmatchpatch"
|
|
||||||
"golang.org/x/net/html/charset"
|
|
||||||
"golang.org/x/text/transform"
|
|
||||||
|
|
||||||
"github.com/gogs/git-module"
|
|
||||||
|
|
||||||
"gogs.io/gogs/internal/conf"
|
|
||||||
"gogs.io/gogs/internal/template/highlight"
|
|
||||||
"gogs.io/gogs/internal/tool"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DiffSection struct {
|
|
||||||
*git.DiffSection
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
addedCodePrefix = []byte("<span class=\"added-code\">")
|
|
||||||
removedCodePrefix = []byte("<span class=\"removed-code\">")
|
|
||||||
codeTagSuffix = []byte("</span>")
|
|
||||||
)
|
|
||||||
|
|
||||||
func diffToHTML(diffs []diffmatchpatch.Diff, lineType git.DiffLineType) template.HTML {
|
|
||||||
buf := bytes.NewBuffer(nil)
|
|
||||||
|
|
||||||
// Reproduce signs which are cutted for inline diff before.
|
|
||||||
switch lineType {
|
|
||||||
case git.DIFF_LINE_ADD:
|
|
||||||
buf.WriteByte('+')
|
|
||||||
case git.DIFF_LINE_DEL:
|
|
||||||
buf.WriteByte('-')
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range diffs {
|
|
||||||
switch {
|
|
||||||
case diffs[i].Type == diffmatchpatch.DiffInsert && lineType == git.DIFF_LINE_ADD:
|
|
||||||
buf.Write(addedCodePrefix)
|
|
||||||
buf.WriteString(html.EscapeString(diffs[i].Text))
|
|
||||||
buf.Write(codeTagSuffix)
|
|
||||||
case diffs[i].Type == diffmatchpatch.DiffDelete && lineType == git.DIFF_LINE_DEL:
|
|
||||||
buf.Write(removedCodePrefix)
|
|
||||||
buf.WriteString(html.EscapeString(diffs[i].Text))
|
|
||||||
buf.Write(codeTagSuffix)
|
|
||||||
case diffs[i].Type == diffmatchpatch.DiffEqual:
|
|
||||||
buf.WriteString(html.EscapeString(diffs[i].Text))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return template.HTML(buf.Bytes())
|
|
||||||
}
|
|
||||||
|
|
||||||
var diffMatchPatch = diffmatchpatch.New()
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
diffMatchPatch.DiffEditCost = 100
|
|
||||||
}
|
|
||||||
|
|
||||||
// ComputedInlineDiffFor computes inline diff for the given line.
|
|
||||||
func (diffSection *DiffSection) ComputedInlineDiffFor(diffLine *git.DiffLine) template.HTML {
|
|
||||||
if conf.Git.DisableDiffHighlight {
|
|
||||||
return template.HTML(html.EscapeString(diffLine.Content[1:]))
|
|
||||||
}
|
|
||||||
var (
|
|
||||||
compareDiffLine *git.DiffLine
|
|
||||||
diff1 string
|
|
||||||
diff2 string
|
|
||||||
)
|
|
||||||
|
|
||||||
// try to find equivalent diff line. ignore, otherwise
|
|
||||||
switch diffLine.Type {
|
|
||||||
case git.DIFF_LINE_ADD:
|
|
||||||
compareDiffLine = diffSection.Line(git.DIFF_LINE_DEL, diffLine.RightIdx)
|
|
||||||
if compareDiffLine == nil {
|
|
||||||
return template.HTML(html.EscapeString(diffLine.Content))
|
|
||||||
}
|
|
||||||
diff1 = compareDiffLine.Content
|
|
||||||
diff2 = diffLine.Content
|
|
||||||
case git.DIFF_LINE_DEL:
|
|
||||||
compareDiffLine = diffSection.Line(git.DIFF_LINE_ADD, diffLine.LeftIdx)
|
|
||||||
if compareDiffLine == nil {
|
|
||||||
return template.HTML(html.EscapeString(diffLine.Content))
|
|
||||||
}
|
|
||||||
diff1 = diffLine.Content
|
|
||||||
diff2 = compareDiffLine.Content
|
|
||||||
default:
|
|
||||||
return template.HTML(html.EscapeString(diffLine.Content))
|
|
||||||
}
|
|
||||||
|
|
||||||
diffRecord := diffMatchPatch.DiffMain(diff1[1:], diff2[1:], true)
|
|
||||||
diffRecord = diffMatchPatch.DiffCleanupEfficiency(diffRecord)
|
|
||||||
|
|
||||||
return diffToHTML(diffRecord, diffLine.Type)
|
|
||||||
}
|
|
||||||
|
|
||||||
type DiffFile struct {
|
|
||||||
*git.DiffFile
|
|
||||||
Sections []*DiffSection
|
|
||||||
}
|
|
||||||
|
|
||||||
func (diffFile *DiffFile) HighlightClass() string {
|
|
||||||
return highlight.FileNameToHighlightClass(diffFile.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Diff struct {
|
|
||||||
*git.Diff
|
|
||||||
Files []*DiffFile
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDiff(gitDiff *git.Diff) *Diff {
|
|
||||||
diff := &Diff{
|
|
||||||
Diff: gitDiff,
|
|
||||||
Files: make([]*DiffFile, gitDiff.NumFiles()),
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: detect encoding while parsing.
|
|
||||||
var buf bytes.Buffer
|
|
||||||
for i := range gitDiff.Files {
|
|
||||||
buf.Reset()
|
|
||||||
|
|
||||||
diff.Files[i] = &DiffFile{
|
|
||||||
DiffFile: gitDiff.Files[i],
|
|
||||||
Sections: make([]*DiffSection, gitDiff.Files[i].NumSections()),
|
|
||||||
}
|
|
||||||
|
|
||||||
for j := range gitDiff.Files[i].Sections {
|
|
||||||
diff.Files[i].Sections[j] = &DiffSection{
|
|
||||||
DiffSection: gitDiff.Files[i].Sections[j],
|
|
||||||
}
|
|
||||||
|
|
||||||
for k := range diff.Files[i].Sections[j].Lines {
|
|
||||||
buf.WriteString(diff.Files[i].Sections[j].Lines[k].Content)
|
|
||||||
buf.WriteString("\n")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
charsetLabel, err := tool.DetectEncoding(buf.Bytes())
|
|
||||||
if charsetLabel != "UTF-8" && err == nil {
|
|
||||||
encoding, _ := charset.Lookup(charsetLabel)
|
|
||||||
if encoding != nil {
|
|
||||||
d := encoding.NewDecoder()
|
|
||||||
for j := range diff.Files[i].Sections {
|
|
||||||
for k := range diff.Files[i].Sections[j].Lines {
|
|
||||||
if c, _, err := transform.String(d, diff.Files[i].Sections[j].Lines[k].Content); err == nil {
|
|
||||||
diff.Files[i].Sections[j].Lines[k].Content = c
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return diff
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParsePatch(maxLines, maxLineCharacteres, maxFiles int, reader io.Reader) (*Diff, error) {
|
|
||||||
done := make(chan error)
|
|
||||||
var gitDiff *git.Diff
|
|
||||||
go func() {
|
|
||||||
gitDiff = git.ParsePatch(done, maxLines, maxLineCharacteres, maxFiles, reader)
|
|
||||||
}()
|
|
||||||
|
|
||||||
if err := <-done; err != nil {
|
|
||||||
return nil, fmt.Errorf("ParsePatch: %v", err)
|
|
||||||
}
|
|
||||||
return NewDiff(gitDiff), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetDiffRange(repoPath, beforeCommitID, afterCommitID string, maxLines, maxLineCharacteres, maxFiles int) (*Diff, error) {
|
|
||||||
gitDiff, err := git.GetDiffRange(repoPath, beforeCommitID, afterCommitID, maxLines, maxLineCharacteres, maxFiles)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("GetDiffRange: %v", err)
|
|
||||||
}
|
|
||||||
return NewDiff(gitDiff), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetDiffCommit(repoPath, commitID string, maxLines, maxLineCharacteres, maxFiles int) (*Diff, error) {
|
|
||||||
gitDiff, err := git.GetDiffCommit(repoPath, commitID, maxLines, maxLineCharacteres, maxFiles)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("GetDiffCommit: %v", err)
|
|
||||||
}
|
|
||||||
return NewDiff(gitDiff), nil
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
// Copyright 2016 The Gogs Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a MIT-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package db
|
|
||||||
|
|
||||||
import (
|
|
||||||
"html/template"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/gogs/git-module"
|
|
||||||
dmp "github.com/sergi/go-diff/diffmatchpatch"
|
|
||||||
)
|
|
||||||
|
|
||||||
func assertEqual(t *testing.T, s1 string, s2 template.HTML) {
|
|
||||||
if s1 != string(s2) {
|
|
||||||
t.Errorf("%s should be equal %s", s2, s1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_diffToHTML(t *testing.T) {
|
|
||||||
assertEqual(t, "+foo <span class=\"added-code\">bar</span> biz", diffToHTML([]dmp.Diff{
|
|
||||||
{Type: dmp.DiffEqual, Text: "foo "},
|
|
||||||
{Type: dmp.DiffInsert, Text: "bar"},
|
|
||||||
{Type: dmp.DiffDelete, Text: " baz"},
|
|
||||||
{Type: dmp.DiffEqual, Text: " biz"},
|
|
||||||
}, git.DiffLineAdd))
|
|
||||||
|
|
||||||
assertEqual(t, "-foo <span class=\"removed-code\">bar</span> biz", diffToHTML([]dmp.Diff{
|
|
||||||
{Type: dmp.DiffEqual, Text: "foo "},
|
|
||||||
{Type: dmp.DiffDelete, Text: "bar"},
|
|
||||||
{Type: dmp.DiffInsert, Text: " baz"},
|
|
||||||
{Type: dmp.DiffEqual, Text: " biz"},
|
|
||||||
}, git.DiffLineDel))
|
|
||||||
}
|
|
||||||
@@ -18,7 +18,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func updateRepositorySizes(x *xorm.Engine) (err error) {
|
func updateRepositorySizes(x *xorm.Engine) (err error) {
|
||||||
log.Info("This migration could take up to minutes, please be patient.")
|
log.Info("[migrations.v16] This migration could take up to minutes, please be patient.")
|
||||||
type Repository struct {
|
type Repository struct {
|
||||||
ID int64
|
ID int64
|
||||||
OwnerID int64
|
OwnerID int64
|
||||||
@@ -41,7 +41,7 @@ func updateRepositorySizes(x *xorm.Engine) (err error) {
|
|||||||
Find(&repos); err != nil {
|
Find(&repos); err != nil {
|
||||||
return fmt.Errorf("select repos [offset: %d]: %v", offset, err)
|
return fmt.Errorf("select repos [offset: %d]: %v", offset, err)
|
||||||
}
|
}
|
||||||
log.Trace("Select [offset: %d, repos: %d]", offset, len(repos))
|
log.Trace("[migrations.v16] Select [offset: %d, repos: %d]", offset, len(repos))
|
||||||
if len(repos) == 0 {
|
if len(repos) == 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -60,10 +60,10 @@ func updateRepositorySizes(x *xorm.Engine) (err error) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
repoPath := filepath.Join(conf.Repository.Root, strings.ToLower(user.Name), strings.ToLower(repo.Name)) + ".git"
|
repoPath := strings.ToLower(filepath.Join(conf.Repository.Root, user.Name, repo.Name)) + ".git"
|
||||||
countObject, err := git.GetRepoSize(repoPath)
|
countObject, err := git.RepoCountObjects(repoPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn("GetRepoSize: %v", err)
|
log.Warn("[migrations.v16] Count repository objects: %v", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
package db
|
package db
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"container/list"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -72,54 +71,17 @@ func (m *Mirror) ScheduleNextSync() {
|
|||||||
m.NextSync = time.Now().Add(time.Duration(m.Interval) * time.Hour)
|
m.NextSync = time.Now().Add(time.Duration(m.Interval) * time.Hour)
|
||||||
}
|
}
|
||||||
|
|
||||||
// findPasswordInMirrorAddress returns start (inclusive) and end index (exclusive)
|
|
||||||
// of password portion of credentials in given mirror address.
|
|
||||||
// It returns a boolean value to indicate whether password portion is found.
|
|
||||||
func findPasswordInMirrorAddress(addr string) (start int, end int, found bool) {
|
|
||||||
// Find end of credentials (start of path)
|
|
||||||
end = strings.LastIndex(addr, "@")
|
|
||||||
if end == -1 {
|
|
||||||
return -1, -1, false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find delimiter of credentials (end of username)
|
|
||||||
start = strings.Index(addr, "://")
|
|
||||||
if start == -1 {
|
|
||||||
return -1, -1, false
|
|
||||||
}
|
|
||||||
start += 3
|
|
||||||
delim := strings.Index(addr[start:], ":")
|
|
||||||
if delim == -1 {
|
|
||||||
return -1, -1, false
|
|
||||||
}
|
|
||||||
delim += 1
|
|
||||||
|
|
||||||
if start+delim >= end {
|
|
||||||
return -1, -1, false // No password portion presented
|
|
||||||
}
|
|
||||||
|
|
||||||
return start + delim, end, true
|
|
||||||
}
|
|
||||||
|
|
||||||
// unescapeMirrorCredentials returns mirror address with unescaped credentials.
|
|
||||||
func unescapeMirrorCredentials(addr string) string {
|
|
||||||
start, end, found := findPasswordInMirrorAddress(addr)
|
|
||||||
if !found {
|
|
||||||
return addr
|
|
||||||
}
|
|
||||||
|
|
||||||
password, _ := url.QueryUnescape(addr[start:end])
|
|
||||||
return addr[:start] + password + addr[end:]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Mirror) readAddress() {
|
func (m *Mirror) readAddress() {
|
||||||
if len(m.address) > 0 {
|
if len(m.address) > 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg, err := ini.Load(m.Repo.GitConfigPath())
|
cfg, err := ini.LoadSources(
|
||||||
|
ini.LoadOptions{IgnoreInlineComment: true},
|
||||||
|
m.Repo.GitConfigPath(),
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Load: %v", err)
|
log.Error("load config: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
m.address = cfg.Section("remote \"origin\"").Key("url").Value()
|
m.address = cfg.Section("remote \"origin\"").Key("url").Value()
|
||||||
@@ -128,6 +90,7 @@ func (m *Mirror) readAddress() {
|
|||||||
// HandleMirrorCredentials replaces user credentials from HTTP/HTTPS URL
|
// HandleMirrorCredentials replaces user credentials from HTTP/HTTPS URL
|
||||||
// with placeholder <credentials>.
|
// with placeholder <credentials>.
|
||||||
// It returns original string if protocol is not HTTP/HTTPS.
|
// It returns original string if protocol is not HTTP/HTTPS.
|
||||||
|
// TODO(unknwon): Use url.Parse.
|
||||||
func HandleMirrorCredentials(url string, mosaics bool) string {
|
func HandleMirrorCredentials(url string, mosaics bool) string {
|
||||||
i := strings.Index(url, "@")
|
i := strings.Index(url, "@")
|
||||||
if i == -1 {
|
if i == -1 {
|
||||||
@@ -161,34 +124,21 @@ func (m *Mirror) RawAddress() string {
|
|||||||
return m.address
|
return m.address
|
||||||
}
|
}
|
||||||
|
|
||||||
// FullAddress returns mirror address from Git repository config with unescaped credentials.
|
|
||||||
func (m *Mirror) FullAddress() string {
|
|
||||||
m.readAddress()
|
|
||||||
return unescapeMirrorCredentials(m.address)
|
|
||||||
}
|
|
||||||
|
|
||||||
// escapeCredentials returns mirror address with escaped credentials.
|
|
||||||
func escapeMirrorCredentials(addr string) string {
|
|
||||||
start, end, found := findPasswordInMirrorAddress(addr)
|
|
||||||
if !found {
|
|
||||||
return addr
|
|
||||||
}
|
|
||||||
|
|
||||||
return addr[:start] + url.QueryEscape(addr[start:end]) + addr[end:]
|
|
||||||
}
|
|
||||||
|
|
||||||
// SaveAddress writes new address to Git repository config.
|
// SaveAddress writes new address to Git repository config.
|
||||||
func (m *Mirror) SaveAddress(addr string) error {
|
func (m *Mirror) SaveAddress(addr string) error {
|
||||||
repoPath := m.Repo.RepoPath()
|
repoPath := m.Repo.RepoPath()
|
||||||
|
|
||||||
err := git.RemoveRemote(repoPath, "origin")
|
err := git.RepoRemoveRemote(repoPath, "origin")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("remove remote 'origin': %v", err)
|
return fmt.Errorf("remove remote 'origin': %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = git.AddRemote(repoPath, "origin", addr, git.AddRemoteOptions{
|
addrURL, err := url.Parse(addr)
|
||||||
Mirror: true,
|
if err != nil {
|
||||||
})
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = git.RepoAddRemote(repoPath, "origin", addrURL.String(), git.AddRemoteOptions{MirrorFetch: true})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("add remote 'origin': %v", err)
|
return fmt.Errorf("add remote 'origin': %v", err)
|
||||||
}
|
}
|
||||||
@@ -196,7 +146,7 @@ func (m *Mirror) SaveAddress(addr string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
const GIT_SHORT_EMPTY_SHA = "0000000"
|
const gitShortEmptyID = "0000000"
|
||||||
|
|
||||||
// mirrorSyncResult contains information of a updated reference.
|
// mirrorSyncResult contains information of a updated reference.
|
||||||
// If the oldCommitID is "0000000", it means a new reference, the value of newCommitID is empty.
|
// If the oldCommitID is "0000000", it means a new reference, the value of newCommitID is empty.
|
||||||
@@ -223,12 +173,12 @@ func parseRemoteUpdateOutput(output string) []*mirrorSyncResult {
|
|||||||
case strings.HasPrefix(lines[i], " * "): // New reference
|
case strings.HasPrefix(lines[i], " * "): // New reference
|
||||||
results = append(results, &mirrorSyncResult{
|
results = append(results, &mirrorSyncResult{
|
||||||
refName: refName,
|
refName: refName,
|
||||||
oldCommitID: GIT_SHORT_EMPTY_SHA,
|
oldCommitID: gitShortEmptyID,
|
||||||
})
|
})
|
||||||
case strings.HasPrefix(lines[i], " - "): // Delete reference
|
case strings.HasPrefix(lines[i], " - "): // Delete reference
|
||||||
results = append(results, &mirrorSyncResult{
|
results = append(results, &mirrorSyncResult{
|
||||||
refName: refName,
|
refName: refName,
|
||||||
newCommitID: GIT_SHORT_EMPTY_SHA,
|
newCommitID: gitShortEmptyID,
|
||||||
})
|
})
|
||||||
case strings.HasPrefix(lines[i], " "): // New commits of a reference
|
case strings.HasPrefix(lines[i], " "): // New commits of a reference
|
||||||
delimIdx := strings.Index(lines[i][3:], " ")
|
delimIdx := strings.Index(lines[i][3:], " ")
|
||||||
@@ -262,10 +212,7 @@ func (m *Mirror) runSync() ([]*mirrorSyncResult, bool) {
|
|||||||
|
|
||||||
// Do a fast-fail testing against on repository URL to ensure it is accessible under
|
// Do a fast-fail testing against on repository URL to ensure it is accessible under
|
||||||
// good condition to prevent long blocking on URL resolution without syncing anything.
|
// good condition to prevent long blocking on URL resolution without syncing anything.
|
||||||
if !git.IsRepoURLAccessible(git.NetworkOptions{
|
if !git.IsURLAccessible(time.Minute, m.RawAddress()) {
|
||||||
URL: m.RawAddress(),
|
|
||||||
Timeout: 10 * time.Second,
|
|
||||||
}) {
|
|
||||||
desc := fmt.Sprintf("Source URL of mirror repository '%s' is not accessible: %s", m.Repo.FullName(), m.MosaicsAddress())
|
desc := fmt.Sprintf("Source URL of mirror repository '%s' is not accessible: %s", m.Repo.FullName(), m.MosaicsAddress())
|
||||||
if err := CreateRepositoryNotice(desc); err != nil {
|
if err := CreateRepositoryNotice(desc); err != nil {
|
||||||
log.Error("CreateRepositoryNotice: %v", err)
|
log.Error("CreateRepositoryNotice: %v", err)
|
||||||
@@ -393,15 +340,14 @@ func SyncMirrors() {
|
|||||||
// - Create "Mirror Sync" webhook event
|
// - Create "Mirror Sync" webhook event
|
||||||
// - Create mirror sync (create, push and delete) events and trigger the "mirror sync" webhooks
|
// - Create mirror sync (create, push and delete) events and trigger the "mirror sync" webhooks
|
||||||
|
|
||||||
var gitRepo *git.Repository
|
|
||||||
if len(results) == 0 {
|
if len(results) == 0 {
|
||||||
log.Trace("SyncMirrors [repo_id: %d]: no commits fetched", m.RepoID)
|
log.Trace("SyncMirrors [repo_id: %d]: no commits fetched", m.RepoID)
|
||||||
} else {
|
|
||||||
gitRepo, err = git.OpenRepository(m.Repo.RepoPath())
|
|
||||||
if err != nil {
|
|
||||||
log.Error("OpenRepository [%d]: %v", m.RepoID, err)
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gitRepo, err := git.Open(m.Repo.RepoPath())
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to open repository [repo_id: %d]: %v", m.RepoID, err)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, result := range results {
|
for _, result := range results {
|
||||||
@@ -411,7 +357,7 @@ func SyncMirrors() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Delete reference
|
// Delete reference
|
||||||
if result.newCommitID == GIT_SHORT_EMPTY_SHA {
|
if result.newCommitID == gitShortEmptyID {
|
||||||
if err = MirrorSyncDeleteAction(m.Repo, result.refName); err != nil {
|
if err = MirrorSyncDeleteAction(m.Repo, result.refName); err != nil {
|
||||||
log.Error("MirrorSyncDeleteAction [repo_id: %d]: %v", m.RepoID, err)
|
log.Error("MirrorSyncDeleteAction [repo_id: %d]: %v", m.RepoID, err)
|
||||||
}
|
}
|
||||||
@@ -420,7 +366,7 @@ func SyncMirrors() {
|
|||||||
|
|
||||||
// New reference
|
// New reference
|
||||||
isNewRef := false
|
isNewRef := false
|
||||||
if result.oldCommitID == GIT_SHORT_EMPTY_SHA {
|
if result.oldCommitID == gitShortEmptyID {
|
||||||
if err = MirrorSyncCreateAction(m.Repo, result.refName); err != nil {
|
if err = MirrorSyncCreateAction(m.Repo, result.refName); err != nil {
|
||||||
log.Error("MirrorSyncCreateAction [repo_id: %d]: %v", m.RepoID, err)
|
log.Error("MirrorSyncCreateAction [repo_id: %d]: %v", m.RepoID, err)
|
||||||
continue
|
continue
|
||||||
@@ -429,49 +375,52 @@ func SyncMirrors() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Push commits
|
// Push commits
|
||||||
var commits *list.List
|
var commits []*git.Commit
|
||||||
var oldCommitID string
|
var oldCommitID string
|
||||||
var newCommitID string
|
var newCommitID string
|
||||||
if !isNewRef {
|
if !isNewRef {
|
||||||
oldCommitID, err = git.GetFullCommitID(gitRepo.Path, result.oldCommitID)
|
oldCommitID, err = gitRepo.RevParse(result.oldCommitID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetFullCommitID [%d]: %v", m.RepoID, err)
|
log.Error("Failed to parse revision [repo_id: %d, old_commit_id: %s]: %v", m.RepoID, result.oldCommitID, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
newCommitID, err = git.GetFullCommitID(gitRepo.Path, result.newCommitID)
|
newCommitID, err = gitRepo.RevParse(result.newCommitID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetFullCommitID [%d]: %v", m.RepoID, err)
|
log.Error("Failed to parse revision [repo_id: %d, new_commit_id: %s]: %v", m.RepoID, result.newCommitID, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
commits, err = gitRepo.CommitsBetweenIDs(newCommitID, oldCommitID)
|
commits, err = gitRepo.RevList([]string{oldCommitID + "..." + newCommitID})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("CommitsBetweenIDs [repo_id: %d, new_commit_id: %s, old_commit_id: %s]: %v", m.RepoID, newCommitID, oldCommitID, err)
|
log.Error("Failed to list commits [repo_id: %d, old_commit_id: %s, new_commit_id: %s]: %v", m.RepoID, oldCommitID, newCommitID, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
refNewCommitID, err := gitRepo.GetBranchCommitID(result.refName)
|
} else if gitRepo.HasBranch(result.refName) {
|
||||||
|
refNewCommit, err := gitRepo.BranchCommit(result.refName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetFullCommitID [%d]: %v", m.RepoID, err)
|
log.Error("Failed to get branch commit [repo_id: %d, branch: %s]: %v", m.RepoID, result.refName, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if newCommit, err := gitRepo.GetCommit(refNewCommitID); err != nil {
|
|
||||||
log.Error("GetCommit [repo_id: %d, commit_id: %s]: %v", m.RepoID, refNewCommitID, err)
|
// TODO(unknwon): Get the commits for the new ref until the closest ancestor branch like GitHub does.
|
||||||
continue
|
commits, err = refNewCommit.Ancestors(git.LogOptions{MaxCount: 9})
|
||||||
} else {
|
|
||||||
// TODO: Get the commits for the new ref until the closest ancestor branch like Github does
|
|
||||||
commits, err = newCommit.CommitsBeforeLimit(10)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("CommitsBeforeLimit [repo_id: %d, commit_id: %s]: %v", m.RepoID, refNewCommitID, err)
|
log.Error("Failed to get ancestors [repo_id: %d, commit_id: %s]: %v", m.RepoID, refNewCommit.ID, err)
|
||||||
}
|
continue
|
||||||
oldCommitID = git.EMPTY_SHA
|
|
||||||
newCommitID = refNewCommitID
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Put the latest commit in front of ancestors
|
||||||
|
commits = append([]*git.Commit{refNewCommit}, commits...)
|
||||||
|
|
||||||
|
oldCommitID = git.EmptyID
|
||||||
|
newCommitID = refNewCommit.ID.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = MirrorSyncPushAction(m.Repo, MirrorSyncPushActionOptions{
|
if err = MirrorSyncPushAction(m.Repo, MirrorSyncPushActionOptions{
|
||||||
RefName: result.refName,
|
RefName: result.refName,
|
||||||
OldCommitID: oldCommitID,
|
OldCommitID: oldCommitID,
|
||||||
NewCommitID: newCommitID,
|
NewCommitID: newCommitID,
|
||||||
Commits: ListToPushCommits(commits),
|
Commits: CommitsToPushCommits(commits),
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
log.Error("MirrorSyncPushAction [repo_id: %d]: %v", m.RepoID, err)
|
log.Error("MirrorSyncPushAction [repo_id: %d]: %v", m.RepoID, err)
|
||||||
continue
|
continue
|
||||||
@@ -485,15 +434,15 @@ func SyncMirrors() {
|
|||||||
|
|
||||||
// Get latest commit date and compare to current repository updated time,
|
// Get latest commit date and compare to current repository updated time,
|
||||||
// update if latest commit date is newer.
|
// update if latest commit date is newer.
|
||||||
commitDate, err := git.GetLatestCommitDate(m.Repo.RepoPath(), "")
|
latestCommitTime, err := gitRepo.LatestCommitTime()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetLatestCommitDate [%d]: %v", m.RepoID, err)
|
log.Error("GetLatestCommitDate [%d]: %v", m.RepoID, err)
|
||||||
continue
|
continue
|
||||||
} else if commitDate.Before(m.Repo.Updated) {
|
} else if !latestCommitTime.After(m.Repo.Updated) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = x.Exec("UPDATE repository SET updated_unix = ? WHERE id = ?", commitDate.Unix(), m.RepoID); err != nil {
|
if _, err = x.Exec("UPDATE repository SET updated_unix = ? WHERE id = ?", latestCommitTime.Unix(), m.RepoID); err != nil {
|
||||||
log.Error("Update 'repository.updated_unix' [%d]: %v", m.RepoID, err)
|
log.Error("Update 'repository.updated_unix' [%d]: %v", m.RepoID, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,14 +7,13 @@ package db
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
. "github.com/smartystreets/goconvey/convey"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_parseRemoteUpdateOutput(t *testing.T) {
|
func Test_parseRemoteUpdateOutput(t *testing.T) {
|
||||||
Convey("Parse mirror remote update output", t, func() {
|
tests := []struct {
|
||||||
testCases := []struct {
|
|
||||||
output string
|
output string
|
||||||
results []*mirrorSyncResult
|
expResults []*mirrorSyncResult
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
`
|
`
|
||||||
@@ -24,85 +23,15 @@ From https://try.gogs.io/unknwon/upsteam
|
|||||||
- [deleted] (none) -> bugfix
|
- [deleted] (none) -> bugfix
|
||||||
`,
|
`,
|
||||||
[]*mirrorSyncResult{
|
[]*mirrorSyncResult{
|
||||||
{"develop", GIT_SHORT_EMPTY_SHA, ""},
|
{"develop", gitShortEmptyID, ""},
|
||||||
{"master", "b0bb24f", "1d85a4f"},
|
{"master", "b0bb24f", "1d85a4f"},
|
||||||
{"bugfix", "", GIT_SHORT_EMPTY_SHA},
|
{"bugfix", "", gitShortEmptyID},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
for _, test := range tests {
|
||||||
for _, tc := range testCases {
|
t.Run("", func(t *testing.T) {
|
||||||
results := parseRemoteUpdateOutput(tc.output)
|
assert.Equal(t, test.expResults, parseRemoteUpdateOutput(test.output))
|
||||||
So(len(results), ShouldEqual, len(tc.results))
|
|
||||||
|
|
||||||
for i := range tc.results {
|
|
||||||
So(tc.results[i].refName, ShouldEqual, results[i].refName)
|
|
||||||
So(tc.results[i].oldCommitID, ShouldEqual, results[i].oldCommitID)
|
|
||||||
So(tc.results[i].newCommitID, ShouldEqual, results[i].newCommitID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_findPasswordInMirrorAddress(t *testing.T) {
|
|
||||||
Convey("Find password portion in mirror address", t, func() {
|
|
||||||
testCases := []struct {
|
|
||||||
addr string
|
|
||||||
start, end int
|
|
||||||
found bool
|
|
||||||
password string
|
|
||||||
}{
|
|
||||||
{"http://localhost:3000/user/repo.git", -1, -1, false, ""},
|
|
||||||
{"http://user@localhost:3000/user/repo.git", -1, -1, false, ""},
|
|
||||||
{"http://user:@localhost:3000/user/repo.git", -1, -1, false, ""},
|
|
||||||
{"http://user:password@localhost:3000/user/repo.git", 12, 20, true, "password"},
|
|
||||||
{"http://username:my%3Asecure%3Bpassword@localhost:3000/user/repo.git", 16, 38, true, "my%3Asecure%3Bpassword"},
|
|
||||||
{"http://username:my%40secure%23password@localhost:3000/user/repo.git", 16, 38, true, "my%40secure%23password"},
|
|
||||||
{"http://username:@@localhost:3000/user/repo.git", 16, 17, true, "@"},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
|
||||||
start, end, found := findPasswordInMirrorAddress(tc.addr)
|
|
||||||
So(start, ShouldEqual, tc.start)
|
|
||||||
So(end, ShouldEqual, tc.end)
|
|
||||||
So(found, ShouldEqual, tc.found)
|
|
||||||
if found {
|
|
||||||
So(tc.addr[start:end], ShouldEqual, tc.password)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_unescapeMirrorCredentials(t *testing.T) {
|
|
||||||
Convey("Escape credentials in mirror address", t, func() {
|
|
||||||
testCases := []string{
|
|
||||||
"http://localhost:3000/user/repo.git", "http://localhost:3000/user/repo.git",
|
|
||||||
"http://user@localhost:3000/user/repo.git", "http://user@localhost:3000/user/repo.git",
|
|
||||||
"http://user:@localhost:3000/user/repo.git", "http://user:@localhost:3000/user/repo.git",
|
|
||||||
"http://user:password@localhost:3000/user/repo.git", "http://user:password@localhost:3000/user/repo.git",
|
|
||||||
"http://user:my%3Asecure%3Bpassword@localhost:3000/user/repo.git", "http://user:my:secure;password@localhost:3000/user/repo.git",
|
|
||||||
"http://user:my%40secure%23password@localhost:3000/user/repo.git", "http://user:my@secure#password@localhost:3000/user/repo.git",
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < len(testCases); i += 2 {
|
|
||||||
So(unescapeMirrorCredentials(testCases[i]), ShouldEqual, testCases[i+1])
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_escapeMirrorCredentials(t *testing.T) {
|
|
||||||
Convey("Escape credentials in mirror address", t, func() {
|
|
||||||
testCases := []string{
|
|
||||||
"http://localhost:3000/user/repo.git", "http://localhost:3000/user/repo.git",
|
|
||||||
"http://user@localhost:3000/user/repo.git", "http://user@localhost:3000/user/repo.git",
|
|
||||||
"http://user:@localhost:3000/user/repo.git", "http://user:@localhost:3000/user/repo.git",
|
|
||||||
"http://user:password@localhost:3000/user/repo.git", "http://user:password@localhost:3000/user/repo.git",
|
|
||||||
"http://user:my:secure;password@localhost:3000/user/repo.git", "http://user:my%3Asecure%3Bpassword@localhost:3000/user/repo.git",
|
|
||||||
"http://user:my@secure#password@localhost:3000/user/repo.git", "http://user:my%40secure%23password@localhost:3000/user/repo.git",
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < len(testCases); i += 2 {
|
|
||||||
So(escapeMirrorCredentials(testCases[i]), ShouldEqual, testCases[i+1])
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ package db
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -212,9 +211,9 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle
|
|||||||
}
|
}
|
||||||
|
|
||||||
headRepoPath := RepoPath(pr.HeadUserName, pr.HeadRepo.Name)
|
headRepoPath := RepoPath(pr.HeadUserName, pr.HeadRepo.Name)
|
||||||
headGitRepo, err := git.OpenRepository(headRepoPath)
|
headGitRepo, err := git.Open(headRepoPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("OpenRepository: %v", err)
|
return fmt.Errorf("open repository: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create temporary directory to store temporary copy of the base repository,
|
// Create temporary directory to store temporary copy of the base repository,
|
||||||
@@ -228,7 +227,7 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle
|
|||||||
var stderr string
|
var stderr string
|
||||||
if _, stderr, err = process.ExecTimeout(5*time.Minute,
|
if _, stderr, err = process.ExecTimeout(5*time.Minute,
|
||||||
fmt.Sprintf("PullRequest.Merge (git clone): %s", tmpBasePath),
|
fmt.Sprintf("PullRequest.Merge (git clone): %s", tmpBasePath),
|
||||||
"git", "clone", "-b", pr.BaseBranch, baseGitRepo.Path, tmpBasePath); err != nil {
|
"git", "clone", "-b", pr.BaseBranch, baseGitRepo.Path(), tmpBasePath); err != nil {
|
||||||
return fmt.Errorf("git clone: %s", stderr)
|
return fmt.Errorf("git clone: %s", stderr)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,13 +310,13 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle
|
|||||||
// Push changes on base branch to upstream.
|
// Push changes on base branch to upstream.
|
||||||
if _, stderr, err = process.ExecDir(-1, tmpBasePath,
|
if _, stderr, err = process.ExecDir(-1, tmpBasePath,
|
||||||
fmt.Sprintf("PullRequest.Merge (git push): %s", tmpBasePath),
|
fmt.Sprintf("PullRequest.Merge (git push): %s", tmpBasePath),
|
||||||
"git", "push", baseGitRepo.Path, pr.BaseBranch); err != nil {
|
"git", "push", baseGitRepo.Path(), pr.BaseBranch); err != nil {
|
||||||
return fmt.Errorf("git push: %s", stderr)
|
return fmt.Errorf("git push: %s", stderr)
|
||||||
}
|
}
|
||||||
|
|
||||||
pr.MergedCommitID, err = headGitRepo.GetBranchCommitID(pr.HeadBranch)
|
pr.MergedCommitID, err = headGitRepo.BranchCommitID(pr.HeadBranch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("GetBranchCommit: %v", err)
|
return fmt.Errorf("get head branch %q commit ID: %v", pr.HeadBranch, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
pr.HasMerged = true
|
pr.HasMerged = true
|
||||||
@@ -351,42 +350,42 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
l, err := headGitRepo.CommitsBetweenIDs(pr.MergedCommitID, pr.MergeBase)
|
commits, err := headGitRepo.RevList([]string{pr.MergeBase + "..." + pr.MergedCommitID})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("CommitsBetweenIDs: %v", err)
|
log.Error("Failed to list commits [merge_base: %s, merged_commit_id: %s]: %v", pr.MergeBase, pr.MergedCommitID, err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// It is possible that head branch is not fully sync with base branch for merge commits,
|
// NOTE: It is possible that head branch is not fully sync with base branch
|
||||||
// so we need to get latest head commit and append merge commit manully
|
// for merge commits, so we need to get latest head commit and append merge
|
||||||
// to avoid strange diff commits produced.
|
// commit manully to avoid strange diff commits produced.
|
||||||
mergeCommit, err := baseGitRepo.GetBranchCommit(pr.BaseBranch)
|
mergeCommit, err := baseGitRepo.BranchCommit(pr.BaseBranch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetBranchCommit: %v", err)
|
log.Error("Failed to get base branch %q commit: %v", pr.BaseBranch, err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if mergeStyle == MERGE_STYLE_REGULAR {
|
if mergeStyle == MERGE_STYLE_REGULAR {
|
||||||
l.PushFront(mergeCommit)
|
commits = append([]*git.Commit{mergeCommit}, commits...)
|
||||||
}
|
}
|
||||||
|
|
||||||
commits, err := ListToPushCommits(l).ToApiPayloadCommits(pr.BaseRepo.RepoPath(), pr.BaseRepo.HTMLURL())
|
pcs, err := CommitsToPushCommits(commits).ToApiPayloadCommits(pr.BaseRepo.RepoPath(), pr.BaseRepo.HTMLURL())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("ToApiPayloadCommits: %v", err)
|
log.Error("Failed to convert to API payload commits: %v", err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
p := &api.PushPayload{
|
p := &api.PushPayload{
|
||||||
Ref: git.BRANCH_PREFIX + pr.BaseBranch,
|
Ref: git.RefsHeads + pr.BaseBranch,
|
||||||
Before: pr.MergeBase,
|
Before: pr.MergeBase,
|
||||||
After: mergeCommit.ID.String(),
|
After: mergeCommit.ID.String(),
|
||||||
CompareURL: conf.Server.ExternalURL + pr.BaseRepo.ComposeCompareURL(pr.MergeBase, pr.MergedCommitID),
|
CompareURL: conf.Server.ExternalURL + pr.BaseRepo.ComposeCompareURL(pr.MergeBase, pr.MergedCommitID),
|
||||||
Commits: commits,
|
Commits: pcs,
|
||||||
Repo: pr.BaseRepo.APIFormat(nil),
|
Repo: pr.BaseRepo.APIFormat(nil),
|
||||||
Pusher: pr.HeadRepo.MustOwner().APIFormat(),
|
Pusher: pr.HeadRepo.MustOwner().APIFormat(),
|
||||||
Sender: doer.APIFormat(),
|
Sender: doer.APIFormat(),
|
||||||
}
|
}
|
||||||
if err = PrepareWebhooks(pr.BaseRepo, HOOK_EVENT_PUSH, p); err != nil {
|
if err = PrepareWebhooks(pr.BaseRepo, HOOK_EVENT_PUSH, p); err != nil {
|
||||||
log.Error("PrepareWebhooks: %v", err)
|
log.Error("Failed to prepare webhooks: %v", err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -599,36 +598,42 @@ func (pr *PullRequest) UpdatePatch() (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
headGitRepo, err := git.OpenRepository(pr.HeadRepo.RepoPath())
|
headGitRepo, err := git.Open(pr.HeadRepo.RepoPath())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("OpenRepository: %v", err)
|
return fmt.Errorf("open repository: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a temporary remote.
|
// Add a temporary remote.
|
||||||
tmpRemote := com.ToStr(time.Now().UnixNano())
|
tmpRemote := com.ToStr(time.Now().UnixNano())
|
||||||
if err = headGitRepo.AddRemote(tmpRemote, RepoPath(pr.BaseRepo.MustOwner().Name, pr.BaseRepo.Name), true); err != nil {
|
baseRepoPath := RepoPath(pr.BaseRepo.MustOwner().Name, pr.BaseRepo.Name)
|
||||||
return fmt.Errorf("AddRemote: %v", err)
|
err = headGitRepo.AddRemote(tmpRemote, baseRepoPath, git.AddRemoteOptions{Fetch: true})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("add remote %q [repo_id: %d]: %v", tmpRemote, pr.HeadRepoID, err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
headGitRepo.RemoveRemote(tmpRemote)
|
if err := headGitRepo.RemoveRemote(tmpRemote); err != nil {
|
||||||
|
log.Error("Failed to remove remote %q [repo_id: %d]: %v", tmpRemote, pr.HeadRepoID, err)
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
remoteBranch := "remotes/" + tmpRemote + "/" + pr.BaseBranch
|
remoteBranch := "remotes/" + tmpRemote + "/" + pr.BaseBranch
|
||||||
pr.MergeBase, err = headGitRepo.GetMergeBase(remoteBranch, pr.HeadBranch)
|
pr.MergeBase, err = headGitRepo.MergeBase(remoteBranch, pr.HeadBranch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("GetMergeBase: %v", err)
|
return fmt.Errorf("get merge base: %v", err)
|
||||||
} else if err = pr.Update(); err != nil {
|
} else if err = pr.Update(); err != nil {
|
||||||
return fmt.Errorf("Update: %v", err)
|
return fmt.Errorf("update: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
patch, err := headGitRepo.GetPatch(pr.MergeBase, pr.HeadBranch)
|
patch, err := headGitRepo.DiffBinary(pr.MergeBase, pr.HeadBranch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("GetPatch: %v", err)
|
return fmt.Errorf("get binary patch: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = pr.BaseRepo.SavePatch(pr.Index, patch); err != nil {
|
if err = pr.BaseRepo.SavePatch(pr.Index, patch); err != nil {
|
||||||
return fmt.Errorf("BaseRepo.SavePatch: %v", err)
|
return fmt.Errorf("save patch: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Trace("PullRequest[%d].UpdatePatch: patch saved", pr.ID)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -639,25 +644,35 @@ func (pr *PullRequest) PushToBaseRepo() (err error) {
|
|||||||
log.Trace("PushToBaseRepo[%d]: pushing commits to base repo 'refs/pull/%d/head'", pr.BaseRepoID, pr.Index)
|
log.Trace("PushToBaseRepo[%d]: pushing commits to base repo 'refs/pull/%d/head'", pr.BaseRepoID, pr.Index)
|
||||||
|
|
||||||
headRepoPath := pr.HeadRepo.RepoPath()
|
headRepoPath := pr.HeadRepo.RepoPath()
|
||||||
headGitRepo, err := git.OpenRepository(headRepoPath)
|
headGitRepo, err := git.Open(headRepoPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("OpenRepository: %v", err)
|
return fmt.Errorf("open repository: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpRemoteName := fmt.Sprintf("tmp-pull-%d", pr.ID)
|
tmpRemote := fmt.Sprintf("tmp-pull-%d", pr.ID)
|
||||||
if err = headGitRepo.AddRemote(tmpRemoteName, pr.BaseRepo.RepoPath(), false); err != nil {
|
if err = headGitRepo.AddRemote(tmpRemote, pr.BaseRepo.RepoPath()); err != nil {
|
||||||
return fmt.Errorf("headGitRepo.AddRemote: %v", err)
|
return fmt.Errorf("add remote %q [repo_id: %d]: %v", tmpRemote, pr.HeadRepoID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure to remove the remote even if the push fails
|
// Make sure to remove the remote even if the push fails
|
||||||
defer headGitRepo.RemoveRemote(tmpRemoteName)
|
defer func() {
|
||||||
|
if err := headGitRepo.RemoveRemote(tmpRemote); err != nil {
|
||||||
|
log.Error("Failed to remove remote %q [repo_id: %d]: %v", tmpRemote, pr.HeadRepoID, err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
headFile := fmt.Sprintf("refs/pull/%d/head", pr.Index)
|
headRefspec := fmt.Sprintf("refs/pull/%d/head", pr.Index)
|
||||||
|
headFile := filepath.Join(pr.BaseRepo.RepoPath(), headRefspec)
|
||||||
|
if osutil.IsExist(headFile) {
|
||||||
|
err = os.Remove(headFile)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("remove head file [repo_id: %d]: %v", pr.BaseRepoID, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Remove head in case there is a conflict.
|
err = headGitRepo.Push(tmpRemote, fmt.Sprintf("%s:%s", pr.HeadBranch, headRefspec))
|
||||||
os.Remove(path.Join(pr.BaseRepo.RepoPath(), headFile))
|
if err != nil {
|
||||||
|
return fmt.Errorf("push: %v", err)
|
||||||
if err = git.Push(headRepoPath, tmpRemoteName, fmt.Sprintf("%s:%s", pr.HeadBranch, headFile)); err != nil {
|
|
||||||
return fmt.Errorf("Push: %v", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -119,10 +119,10 @@ func IsReleaseExist(repoID int64, tagName string) (bool, error) {
|
|||||||
func createTag(gitRepo *git.Repository, r *Release) error {
|
func createTag(gitRepo *git.Repository, r *Release) error {
|
||||||
// Only actual create when publish.
|
// Only actual create when publish.
|
||||||
if !r.IsDraft {
|
if !r.IsDraft {
|
||||||
if !gitRepo.IsTagExist(r.TagName) {
|
if !gitRepo.HasTag(r.TagName) {
|
||||||
commit, err := gitRepo.GetBranchCommit(r.Target)
|
commit, err := gitRepo.BranchCommit(r.Target)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("GetBranchCommit: %v", err)
|
return fmt.Errorf("get branch commit: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trim '--' prefix to prevent command line argument vulnerability.
|
// Trim '--' prefix to prevent command line argument vulnerability.
|
||||||
@@ -134,15 +134,15 @@ func createTag(gitRepo *git.Repository, r *Release) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
commit, err := gitRepo.GetTagCommit(r.TagName)
|
commit, err := gitRepo.TagCommit(r.TagName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("GetTagCommit: %v", err)
|
return fmt.Errorf("get tag commit: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
r.Sha1 = commit.ID.String()
|
r.Sha1 = commit.ID.String()
|
||||||
r.NumCommits, err = commit.CommitsCount()
|
r.NumCommits, err = commit.CommitsCount()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("CommitsCount: %v", err)
|
return fmt.Errorf("count commits: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,9 +119,6 @@ func NewRepoContext() {
|
|||||||
if version.Compare("1.8.3", conf.Git.Version, ">") {
|
if version.Compare("1.8.3", conf.Git.Version, ">") {
|
||||||
log.Fatal("Gogs requires Git version greater or equal to 1.8.3")
|
log.Fatal("Gogs requires Git version greater or equal to 1.8.3")
|
||||||
}
|
}
|
||||||
git.HookDir = "custom_hooks"
|
|
||||||
git.HookSampleDir = "hooks"
|
|
||||||
git.DefaultCommitsPageSize = conf.UI.User.CommitsPagingNum
|
|
||||||
|
|
||||||
// Git requires setting user.name and user.email in order to commit changes.
|
// Git requires setting user.name and user.email in order to commit changes.
|
||||||
for configKey, defaultValue := range map[string]string{"user.name": "Gogs", "user.email": "gogs@fake.local"} {
|
for configKey, defaultValue := range map[string]string{"user.name": "Gogs", "user.email": "gogs@fake.local"} {
|
||||||
@@ -420,9 +417,9 @@ func (repo *Repository) mustOwner(e Engine) *User {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (repo *Repository) UpdateSize() error {
|
func (repo *Repository) UpdateSize() error {
|
||||||
countObject, err := git.GetRepoSize(repo.RepoPath())
|
countObject, err := git.RepoCountObjects(repo.RepoPath())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("GetRepoSize: %v", err)
|
return fmt.Errorf("count repository objects: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
repo.Size = countObject.Size + countObject.SizePack
|
repo.Size = countObject.Size + countObject.SizePack
|
||||||
@@ -602,33 +599,41 @@ func (repo *Repository) LocalCopyPath() string {
|
|||||||
// assume subsequent operations are against target branch when caller has confidence
|
// assume subsequent operations are against target branch when caller has confidence
|
||||||
// about no race condition.
|
// about no race condition.
|
||||||
func UpdateLocalCopyBranch(repoPath, localPath, branch string, isWiki bool) (err error) {
|
func UpdateLocalCopyBranch(repoPath, localPath, branch string, isWiki bool) (err error) {
|
||||||
if !com.IsExist(localPath) {
|
if !osutil.IsExist(localPath) {
|
||||||
// Checkout to a specific branch fails when wiki is an empty repository.
|
// Checkout to a specific branch fails when wiki is an empty repository.
|
||||||
if isWiki {
|
if isWiki {
|
||||||
branch = ""
|
branch = ""
|
||||||
}
|
}
|
||||||
if err = git.Clone(repoPath, localPath, git.CloneRepoOptions{
|
if err = git.Clone(repoPath, localPath, git.CloneOptions{
|
||||||
Timeout: time.Duration(conf.Git.Timeout.Clone) * time.Second,
|
|
||||||
Branch: branch,
|
Branch: branch,
|
||||||
|
Timeout: time.Duration(conf.Git.Timeout.Clone) * time.Second,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return fmt.Errorf("git clone %s: %v", branch, err)
|
return fmt.Errorf("git clone [branch: %s]: %v", branch, err)
|
||||||
}
|
}
|
||||||
} else {
|
return nil
|
||||||
if err = git.Fetch(localPath, git.FetchRemoteOptions{
|
}
|
||||||
|
|
||||||
|
gitRepo, err := git.Open(localPath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("open repository: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = gitRepo.Fetch(git.FetchOptions{
|
||||||
Prune: true,
|
Prune: true,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return fmt.Errorf("git fetch: %v", err)
|
return fmt.Errorf("fetch: %v", err)
|
||||||
}
|
}
|
||||||
if err = git.Checkout(localPath, git.CheckoutOptions{
|
|
||||||
Branch: branch,
|
if err = gitRepo.Checkout(branch); err != nil {
|
||||||
}); err != nil {
|
return fmt.Errorf("checkout [branch: %s]: %v", branch, err)
|
||||||
return fmt.Errorf("git checkout %s: %v", branch, err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset to align with remote in case of force push.
|
// Reset to align with remote in case of force push.
|
||||||
if err = git.ResetHEAD(localPath, true, "origin/"+branch); err != nil {
|
rev := "origin/" + branch
|
||||||
return fmt.Errorf("git reset --hard origin/%s: %v", branch, err)
|
if err = gitRepo.Reset(rev, git.ResetOptions{
|
||||||
}
|
Hard: true,
|
||||||
|
}); err != nil {
|
||||||
|
return fmt.Errorf("reset [revision: %s]: %v", rev, err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -729,9 +734,7 @@ func wikiRemoteURL(remote string) string {
|
|||||||
remote = strings.TrimSuffix(remote, ".git")
|
remote = strings.TrimSuffix(remote, ".git")
|
||||||
for _, suffix := range commonWikiURLSuffixes {
|
for _, suffix := range commonWikiURLSuffixes {
|
||||||
wikiURL := remote + suffix
|
wikiURL := remote + suffix
|
||||||
if git.IsRepoURLAccessible(git.NetworkOptions{
|
if git.IsURLAccessible(time.Minute, wikiURL) {
|
||||||
URL: wikiURL,
|
|
||||||
}) {
|
|
||||||
return wikiURL
|
return wikiURL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -766,23 +769,23 @@ func MigrateRepository(doer, owner *User, opts MigrateRepoOptions) (*Repository,
|
|||||||
migrateTimeout := time.Duration(conf.Git.Timeout.Migrate) * time.Second
|
migrateTimeout := time.Duration(conf.Git.Timeout.Migrate) * time.Second
|
||||||
|
|
||||||
RemoveAllWithNotice("Repository path erase before creation", repoPath)
|
RemoveAllWithNotice("Repository path erase before creation", repoPath)
|
||||||
if err = git.Clone(opts.RemoteAddr, repoPath, git.CloneRepoOptions{
|
if err = git.Clone(opts.RemoteAddr, repoPath, git.CloneOptions{
|
||||||
Mirror: true,
|
Mirror: true,
|
||||||
Quiet: true,
|
Quiet: true,
|
||||||
Timeout: migrateTimeout,
|
Timeout: migrateTimeout,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return repo, fmt.Errorf("Clone: %v", err)
|
return repo, fmt.Errorf("clone: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
wikiRemotePath := wikiRemoteURL(opts.RemoteAddr)
|
wikiRemotePath := wikiRemoteURL(opts.RemoteAddr)
|
||||||
if len(wikiRemotePath) > 0 {
|
if len(wikiRemotePath) > 0 {
|
||||||
RemoveAllWithNotice("Repository wiki path erase before creation", wikiPath)
|
RemoveAllWithNotice("Repository wiki path erase before creation", wikiPath)
|
||||||
if err = git.Clone(wikiRemotePath, wikiPath, git.CloneRepoOptions{
|
if err = git.Clone(wikiRemotePath, wikiPath, git.CloneOptions{
|
||||||
Mirror: true,
|
Mirror: true,
|
||||||
Quiet: true,
|
Quiet: true,
|
||||||
Timeout: migrateTimeout,
|
Timeout: migrateTimeout,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
log.Trace("Failed to clone wiki: %v", err)
|
log.Error("Failed to clone wiki: %v", err)
|
||||||
RemoveAllWithNotice("Delete repository wiki for initialization failure", wikiPath)
|
RemoveAllWithNotice("Delete repository wiki for initialization failure", wikiPath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -799,17 +802,15 @@ func MigrateRepository(doer, owner *User, opts MigrateRepoOptions) (*Repository,
|
|||||||
|
|
||||||
if !repo.IsBare {
|
if !repo.IsBare {
|
||||||
// Try to get HEAD branch and set it as default branch.
|
// Try to get HEAD branch and set it as default branch.
|
||||||
gitRepo, err := git.OpenRepository(repoPath)
|
gitRepo, err := git.Open(repoPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return repo, fmt.Errorf("OpenRepository: %v", err)
|
return repo, fmt.Errorf("open repository: %v", err)
|
||||||
}
|
}
|
||||||
headBranch, err := gitRepo.GetHEADBranch()
|
refspec, err := gitRepo.SymbolicRef()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return repo, fmt.Errorf("GetHEADBranch: %v", err)
|
return repo, fmt.Errorf("get HEAD branch: %v", err)
|
||||||
}
|
|
||||||
if headBranch != nil {
|
|
||||||
repo.DefaultBranch = headBranch.Name
|
|
||||||
}
|
}
|
||||||
|
repo.DefaultBranch = git.RefShortName(refspec)
|
||||||
|
|
||||||
if err = repo.UpdateSize(); err != nil {
|
if err = repo.UpdateSize(); err != nil {
|
||||||
log.Error("UpdateSize [repo_id: %d]: %v", repo.ID, err)
|
log.Error("UpdateSize [repo_id: %d]: %v", repo.ID, err)
|
||||||
@@ -847,15 +848,15 @@ func cleanUpMigrateGitConfig(configPath string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var hooksTpls = map[string]string{
|
var hooksTpls = map[git.HookName]string{
|
||||||
"pre-receive": "#!/usr/bin/env %s\n\"%s\" hook --config='%s' pre-receive\n",
|
"pre-receive": "#!/usr/bin/env %s\n\"%s\" hook --config='%s' pre-receive\n",
|
||||||
"update": "#!/usr/bin/env %s\n\"%s\" hook --config='%s' update $1 $2 $3\n",
|
"update": "#!/usr/bin/env %s\n\"%s\" hook --config='%s' update $1 $2 $3\n",
|
||||||
"post-receive": "#!/usr/bin/env %s\n\"%s\" hook --config='%s' post-receive\n",
|
"post-receive": "#!/usr/bin/env %s\n\"%s\" hook --config='%s' post-receive\n",
|
||||||
}
|
}
|
||||||
|
|
||||||
func createDelegateHooks(repoPath string) (err error) {
|
func createDelegateHooks(repoPath string) (err error) {
|
||||||
for _, name := range git.HookNames {
|
for _, name := range git.ServerSideHooks {
|
||||||
hookPath := filepath.Join(repoPath, "hooks", name)
|
hookPath := filepath.Join(repoPath, "hooks", string(name))
|
||||||
if err = ioutil.WriteFile(hookPath,
|
if err = ioutil.WriteFile(hookPath,
|
||||||
[]byte(fmt.Sprintf(hooksTpls[name], conf.Repository.ScriptType, conf.AppPath(), conf.CustomConf)),
|
[]byte(fmt.Sprintf(hooksTpls[name], conf.Repository.ScriptType, conf.AppPath(), conf.CustomConf)),
|
||||||
os.ModePerm); err != nil {
|
os.ModePerm); err != nil {
|
||||||
@@ -1005,8 +1006,8 @@ func initRepository(e Engine, repoPath string, doer *User, repo *Repository, opt
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Init bare new repository.
|
// Init bare new repository.
|
||||||
if err = git.InitRepository(repoPath, true); err != nil {
|
if err = git.Init(repoPath, git.InitOptions{Bare: true}); err != nil {
|
||||||
return fmt.Errorf("InitRepository: %v", err)
|
return fmt.Errorf("init repository: %v", err)
|
||||||
} else if err = createDelegateHooks(repoPath); err != nil {
|
} else if err = createDelegateHooks(repoPath); err != nil {
|
||||||
return fmt.Errorf("createDelegateHooks: %v", err)
|
return fmt.Errorf("createDelegateHooks: %v", err)
|
||||||
}
|
}
|
||||||
@@ -1880,9 +1881,9 @@ func ReinitMissingRepositories() error {
|
|||||||
|
|
||||||
for _, repo := range repos {
|
for _, repo := range repos {
|
||||||
log.Trace("Initializing %d/%d...", repo.OwnerID, repo.ID)
|
log.Trace("Initializing %d/%d...", repo.OwnerID, repo.ID)
|
||||||
if err := git.InitRepository(repo.RepoPath(), true); err != nil {
|
if err := git.Init(repo.RepoPath(), git.InitOptions{Bare: true}); err != nil {
|
||||||
if err2 := CreateRepositoryNotice(fmt.Sprintf("InitRepository [%d]: %v", repo.ID, err)); err2 != nil {
|
if err2 := CreateRepositoryNotice(fmt.Sprintf("init repository [repo_id: %d]: %v", repo.ID, err)); err2 != nil {
|
||||||
return fmt.Errorf("CreateRepositoryNotice: %v", err)
|
return fmt.Errorf("create repository notice: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1930,7 +1931,11 @@ func GitFsck() {
|
|||||||
func(idx int, bean interface{}) error {
|
func(idx int, bean interface{}) error {
|
||||||
repo := bean.(*Repository)
|
repo := bean.(*Repository)
|
||||||
repoPath := repo.RepoPath()
|
repoPath := repo.RepoPath()
|
||||||
if err := git.Fsck(repoPath, conf.Cron.RepoHealthCheck.Timeout, conf.Cron.RepoHealthCheck.Args...); err != nil {
|
err := git.RepoFsck(repoPath, git.FsckOptions{
|
||||||
|
Args: conf.Cron.RepoHealthCheck.Args,
|
||||||
|
Timeout: conf.Cron.RepoHealthCheck.Timeout,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
desc := fmt.Sprintf("Failed to perform health check on repository '%s': %v", repoPath, err)
|
desc := fmt.Sprintf("Failed to perform health check on repository '%s': %v", repoPath, err)
|
||||||
log.Warn(desc)
|
log.Warn(desc)
|
||||||
if err = CreateRepositoryNotice(desc); err != nil {
|
if err = CreateRepositoryNotice(desc); err != nil {
|
||||||
@@ -2441,24 +2446,24 @@ func (repo *Repository) GetForks() ([]*Repository, error) {
|
|||||||
// \/ \/ \/ \/ \/
|
// \/ \/ \/ \/ \/
|
||||||
//
|
//
|
||||||
|
|
||||||
func (repo *Repository) CreateNewBranch(doer *User, oldBranchName, branchName string) (err error) {
|
func (repo *Repository) CreateNewBranch(oldBranch, newBranch string) (err error) {
|
||||||
repoWorkingPool.CheckIn(com.ToStr(repo.ID))
|
repoWorkingPool.CheckIn(com.ToStr(repo.ID))
|
||||||
defer repoWorkingPool.CheckOut(com.ToStr(repo.ID))
|
defer repoWorkingPool.CheckOut(com.ToStr(repo.ID))
|
||||||
|
|
||||||
localPath := repo.LocalCopyPath()
|
localPath := repo.LocalCopyPath()
|
||||||
|
|
||||||
if err = discardLocalRepoBranchChanges(localPath, oldBranchName); err != nil {
|
if err = discardLocalRepoBranchChanges(localPath, oldBranch); err != nil {
|
||||||
return fmt.Errorf("discardLocalRepoChanges: %v", err)
|
return fmt.Errorf("discard changes in local copy [path: %s, branch: %s]: %v", localPath, oldBranch, err)
|
||||||
} else if err = repo.UpdateLocalCopyBranch(oldBranchName); err != nil {
|
} else if err = repo.UpdateLocalCopyBranch(oldBranch); err != nil {
|
||||||
return fmt.Errorf("UpdateLocalCopyBranch: %v", err)
|
return fmt.Errorf("update branch for local copy [path: %s, branch: %s]: %v", localPath, oldBranch, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = repo.CheckoutNewBranch(oldBranchName, branchName); err != nil {
|
if err = repo.CheckoutNewBranch(oldBranch, newBranch); err != nil {
|
||||||
return fmt.Errorf("CreateNewBranch: %v", err)
|
return fmt.Errorf("create new branch [base: %s, new: %s]: %v", oldBranch, newBranch, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = git.Push(localPath, "origin", branchName); err != nil {
|
if err = git.RepoPush(localPath, "origin", newBranch); err != nil {
|
||||||
return fmt.Errorf("Push: %v", err)
|
return fmt.Errorf("push [branch: %s]: %v", newBranch, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -24,33 +24,33 @@ type Branch struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetBranchesByPath(path string) ([]*Branch, error) {
|
func GetBranchesByPath(path string) ([]*Branch, error) {
|
||||||
gitRepo, err := git.OpenRepository(path)
|
gitRepo, err := git.Open(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("open repository: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
brs, err := gitRepo.GetBranches()
|
names, err := gitRepo.Branches()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("list branches")
|
||||||
}
|
}
|
||||||
|
|
||||||
branches := make([]*Branch, len(brs))
|
branches := make([]*Branch, len(names))
|
||||||
for i := range brs {
|
for i := range names {
|
||||||
branches[i] = &Branch{
|
branches[i] = &Branch{
|
||||||
RepoPath: path,
|
RepoPath: path,
|
||||||
Name: brs[i],
|
Name: names[i],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return branches, nil
|
return branches, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *Repository) GetBranch(br string) (*Branch, error) {
|
func (repo *Repository) GetBranch(name string) (*Branch, error) {
|
||||||
if !git.IsBranchExist(repo.RepoPath(), br) {
|
if !git.RepoHasBranch(repo.RepoPath(), name) {
|
||||||
return nil, errors.ErrBranchNotExist{Name: br}
|
return nil, errors.ErrBranchNotExist{Name: name}
|
||||||
}
|
}
|
||||||
return &Branch{
|
return &Branch{
|
||||||
RepoPath: repo.RepoPath(),
|
RepoPath: repo.RepoPath(),
|
||||||
Name: br,
|
Name: name,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,11 +59,11 @@ func (repo *Repository) GetBranches() ([]*Branch, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (br *Branch) GetCommit() (*git.Commit, error) {
|
func (br *Branch) GetCommit() (*git.Commit, error) {
|
||||||
gitRepo, err := git.OpenRepository(br.RepoPath)
|
gitRepo, err := git.Open(br.RepoPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("open repository: %v", err)
|
||||||
}
|
}
|
||||||
return gitRepo.GetBranchCommit(br.Name)
|
return gitRepo.BranchCommit(br.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProtectBranchWhitelist struct {
|
type ProtectBranchWhitelist struct {
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import (
|
|||||||
|
|
||||||
"gogs.io/gogs/internal/conf"
|
"gogs.io/gogs/internal/conf"
|
||||||
"gogs.io/gogs/internal/db/errors"
|
"gogs.io/gogs/internal/db/errors"
|
||||||
|
"gogs.io/gogs/internal/gitutil"
|
||||||
"gogs.io/gogs/internal/osutil"
|
"gogs.io/gogs/internal/osutil"
|
||||||
"gogs.io/gogs/internal/process"
|
"gogs.io/gogs/internal/process"
|
||||||
"gogs.io/gogs/internal/tool"
|
"gogs.io/gogs/internal/tool"
|
||||||
@@ -58,7 +59,7 @@ func ComposeHookEnvs(opts ComposeHookEnvsOptions) []string {
|
|||||||
ENV_REPO_OWNER_SALT_MD5 + "=" + tool.MD5(opts.OwnerSalt),
|
ENV_REPO_OWNER_SALT_MD5 + "=" + tool.MD5(opts.OwnerSalt),
|
||||||
ENV_REPO_ID + "=" + com.ToStr(opts.RepoID),
|
ENV_REPO_ID + "=" + com.ToStr(opts.RepoID),
|
||||||
ENV_REPO_NAME + "=" + opts.RepoName,
|
ENV_REPO_NAME + "=" + opts.RepoName,
|
||||||
ENV_REPO_CUSTOM_HOOKS_PATH + "=" + path.Join(opts.RepoPath, "custom_hooks"),
|
ENV_REPO_CUSTOM_HOOKS_PATH + "=" + filepath.Join(opts.RepoPath, "custom_hooks"),
|
||||||
}
|
}
|
||||||
return envs
|
return envs
|
||||||
}
|
}
|
||||||
@@ -76,14 +77,15 @@ func discardLocalRepoBranchChanges(localPath, branch string) error {
|
|||||||
if !com.IsExist(localPath) {
|
if !com.IsExist(localPath) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// No need to check if nothing in the repository.
|
// No need to check if nothing in the repository.
|
||||||
if !git.IsBranchExist(localPath, branch) {
|
if !git.RepoHasBranch(localPath, branch) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
refName := "origin/" + branch
|
rev := "origin/" + branch
|
||||||
if err := git.ResetHEAD(localPath, true, refName); err != nil {
|
if err := git.RepoReset(localPath, rev, git.ResetOptions{Hard: true}); err != nil {
|
||||||
return fmt.Errorf("git reset --hard %s: %v", refName, err)
|
return fmt.Errorf("reset [revision: %s]: %v", rev, err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -92,22 +94,17 @@ func (repo *Repository) DiscardLocalRepoBranchChanges(branch string) error {
|
|||||||
return discardLocalRepoBranchChanges(repo.LocalCopyPath(), branch)
|
return discardLocalRepoBranchChanges(repo.LocalCopyPath(), branch)
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkoutNewBranch checks out to a new branch from the a branch name.
|
// CheckoutNewBranch checks out to a new branch from the a branch name.
|
||||||
func checkoutNewBranch(repoPath, localPath, oldBranch, newBranch string) error {
|
func (repo *Repository) CheckoutNewBranch(oldBranch, newBranch string) error {
|
||||||
if err := git.Checkout(localPath, git.CheckoutOptions{
|
if err := git.RepoCheckout(repo.LocalCopyPath(), newBranch, git.CheckoutOptions{
|
||||||
|
BaseBranch: oldBranch,
|
||||||
Timeout: time.Duration(conf.Git.Timeout.Pull) * time.Second,
|
Timeout: time.Duration(conf.Git.Timeout.Pull) * time.Second,
|
||||||
Branch: newBranch,
|
|
||||||
OldBranch: oldBranch,
|
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return fmt.Errorf("git checkout -b %s %s: %v", newBranch, oldBranch, err)
|
return fmt.Errorf("checkout [base: %s, new: %s]: %v", oldBranch, newBranch, err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *Repository) CheckoutNewBranch(oldBranch, newBranch string) error {
|
|
||||||
return checkoutNewBranch(repo.RepoPath(), repo.LocalCopyPath(), oldBranch, newBranch)
|
|
||||||
}
|
|
||||||
|
|
||||||
type UpdateRepoFileOptions struct {
|
type UpdateRepoFileOptions struct {
|
||||||
LastCommitID string
|
LastCommitID string
|
||||||
OldBranch string
|
OldBranch string
|
||||||
@@ -135,16 +132,16 @@ func (repo *Repository) UpdateRepoFile(doer *User, opts UpdateRepoFileOptions) (
|
|||||||
|
|
||||||
if opts.OldBranch != opts.NewBranch {
|
if opts.OldBranch != opts.NewBranch {
|
||||||
// Directly return error if new branch already exists in the server
|
// Directly return error if new branch already exists in the server
|
||||||
if git.IsBranchExist(repoPath, opts.NewBranch) {
|
if git.RepoHasBranch(repoPath, opts.NewBranch) {
|
||||||
return errors.BranchAlreadyExists{Name: opts.NewBranch}
|
return errors.BranchAlreadyExists{Name: opts.NewBranch}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, delete branch from local copy in case out of sync
|
// Otherwise, delete branch from local copy in case out of sync
|
||||||
if git.IsBranchExist(localPath, opts.NewBranch) {
|
if git.RepoHasBranch(localPath, opts.NewBranch) {
|
||||||
if err = git.DeleteBranch(localPath, opts.NewBranch, git.DeleteBranchOptions{
|
if err = git.RepoDeleteBranch(localPath, opts.NewBranch, git.DeleteBranchOptions{
|
||||||
Force: true,
|
Force: true,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return fmt.Errorf("delete branch[%s]: %v", opts.NewBranch, err)
|
return fmt.Errorf("delete branch %q: %v", opts.NewBranch, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,7 +164,7 @@ func (repo *Repository) UpdateRepoFile(doer *User, opts UpdateRepoFileOptions) (
|
|||||||
// Ignore move step if it's a new file under a directory.
|
// Ignore move step if it's a new file under a directory.
|
||||||
// Otherwise, move the file when name changed.
|
// Otherwise, move the file when name changed.
|
||||||
if osutil.IsFile(oldFilePath) && opts.OldTreeName != opts.NewTreeName {
|
if osutil.IsFile(oldFilePath) && opts.OldTreeName != opts.NewTreeName {
|
||||||
if err = git.MoveFile(localPath, opts.OldTreeName, opts.NewTreeName); err != nil {
|
if err = git.RepoMove(localPath, opts.OldTreeName, opts.NewTreeName); err != nil {
|
||||||
return fmt.Errorf("git mv %q %q: %v", opts.OldTreeName, opts.NewTreeName, err)
|
return fmt.Errorf("git mv %q %q: %v", opts.OldTreeName, opts.NewTreeName, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -176,29 +173,28 @@ func (repo *Repository) UpdateRepoFile(doer *User, opts UpdateRepoFileOptions) (
|
|||||||
return fmt.Errorf("write file: %v", err)
|
return fmt.Errorf("write file: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = git.AddChanges(localPath, true); err != nil {
|
if err = git.RepoAdd(localPath, git.AddOptions{All: true}); err != nil {
|
||||||
return fmt.Errorf("git add --all: %v", err)
|
return fmt.Errorf("git add --all: %v", err)
|
||||||
} else if err = git.CommitChanges(localPath, git.CommitChangesOptions{
|
} else if err = git.RepoCommit(localPath, doer.NewGitSig(), opts.Message); err != nil {
|
||||||
Committer: doer.NewGitSig(),
|
|
||||||
Message: opts.Message,
|
|
||||||
}); err != nil {
|
|
||||||
return fmt.Errorf("commit changes on %q: %v", localPath, err)
|
return fmt.Errorf("commit changes on %q: %v", localPath, err)
|
||||||
} else if err = git.PushWithEnvs(localPath, "origin", opts.NewBranch,
|
}
|
||||||
ComposeHookEnvs(ComposeHookEnvsOptions{
|
|
||||||
|
envs := ComposeHookEnvs(ComposeHookEnvsOptions{
|
||||||
AuthUser: doer,
|
AuthUser: doer,
|
||||||
OwnerName: repo.MustOwner().Name,
|
OwnerName: repo.MustOwner().Name,
|
||||||
OwnerSalt: repo.MustOwner().Salt,
|
OwnerSalt: repo.MustOwner().Salt,
|
||||||
RepoID: repo.ID,
|
RepoID: repo.ID,
|
||||||
RepoName: repo.Name,
|
RepoName: repo.Name,
|
||||||
RepoPath: repo.RepoPath(),
|
RepoPath: repo.RepoPath(),
|
||||||
})); err != nil {
|
})
|
||||||
|
if err = git.RepoPush(localPath, "origin", opts.NewBranch, git.PushOptions{Envs: envs}); err != nil {
|
||||||
return fmt.Errorf("git push origin %s: %v", opts.NewBranch, err)
|
return fmt.Errorf("git push origin %s: %v", opts.NewBranch, err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDiffPreview produces and returns diff result of a file which is not yet committed.
|
// GetDiffPreview produces and returns diff result of a file which is not yet committed.
|
||||||
func (repo *Repository) GetDiffPreview(branch, treePath, content string) (diff *Diff, err error) {
|
func (repo *Repository) GetDiffPreview(branch, treePath, content string) (diff *gitutil.Diff, err error) {
|
||||||
repoWorkingPool.CheckIn(com.ToStr(repo.ID))
|
repoWorkingPool.CheckIn(com.ToStr(repo.ID))
|
||||||
defer repoWorkingPool.CheckOut(com.ToStr(repo.ID))
|
defer repoWorkingPool.CheckOut(com.ToStr(repo.ID))
|
||||||
|
|
||||||
@@ -231,9 +227,9 @@ func (repo *Repository) GetDiffPreview(branch, treePath, content string) (diff *
|
|||||||
pid := process.Add(fmt.Sprintf("GetDiffPreview [repo_path: %s]", repo.RepoPath()), cmd)
|
pid := process.Add(fmt.Sprintf("GetDiffPreview [repo_path: %s]", repo.RepoPath()), cmd)
|
||||||
defer process.Remove(pid)
|
defer process.Remove(pid)
|
||||||
|
|
||||||
diff, err = ParsePatch(conf.Git.MaxGitDiffLines, conf.Git.MaxGitDiffLineCharacters, conf.Git.MaxGitDiffFiles, stdout)
|
diff, err = gitutil.ParseDiff(stdout, conf.Git.MaxDiffFiles, conf.Git.MaxDiffLines, conf.Git.MaxDiffLineChars)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("parse path: %v", err)
|
return nil, fmt.Errorf("parse diff: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = cmd.Wait(); err != nil {
|
if err = cmd.Wait(); err != nil {
|
||||||
@@ -280,22 +276,21 @@ func (repo *Repository) DeleteRepoFile(doer *User, opts DeleteRepoFileOptions) (
|
|||||||
return fmt.Errorf("remove file %q: %v", opts.TreePath, err)
|
return fmt.Errorf("remove file %q: %v", opts.TreePath, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = git.AddChanges(localPath, true); err != nil {
|
if err = git.RepoAdd(localPath, git.AddOptions{All: true}); err != nil {
|
||||||
return fmt.Errorf("git add --all: %v", err)
|
return fmt.Errorf("git add --all: %v", err)
|
||||||
} else if err = git.CommitChanges(localPath, git.CommitChangesOptions{
|
} else if err = git.RepoCommit(localPath, doer.NewGitSig(), opts.Message); err != nil {
|
||||||
Committer: doer.NewGitSig(),
|
|
||||||
Message: opts.Message,
|
|
||||||
}); err != nil {
|
|
||||||
return fmt.Errorf("commit changes to %q: %v", localPath, err)
|
return fmt.Errorf("commit changes to %q: %v", localPath, err)
|
||||||
} else if err = git.PushWithEnvs(localPath, "origin", opts.NewBranch,
|
}
|
||||||
ComposeHookEnvs(ComposeHookEnvsOptions{
|
|
||||||
|
envs := ComposeHookEnvs(ComposeHookEnvsOptions{
|
||||||
AuthUser: doer,
|
AuthUser: doer,
|
||||||
OwnerName: repo.MustOwner().Name,
|
OwnerName: repo.MustOwner().Name,
|
||||||
OwnerSalt: repo.MustOwner().Salt,
|
OwnerSalt: repo.MustOwner().Salt,
|
||||||
RepoID: repo.ID,
|
RepoID: repo.ID,
|
||||||
RepoName: repo.Name,
|
RepoName: repo.Name,
|
||||||
RepoPath: repo.RepoPath(),
|
RepoPath: repo.RepoPath(),
|
||||||
})); err != nil {
|
})
|
||||||
|
if err = git.RepoPush(localPath, "origin", opts.NewBranch, git.PushOptions{Envs: envs}); err != nil {
|
||||||
return fmt.Errorf("git push origin %s: %v", opts.NewBranch, err)
|
return fmt.Errorf("git push origin %s: %v", opts.NewBranch, err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -496,22 +491,21 @@ func (repo *Repository) UploadRepoFiles(doer *User, opts UploadRepoFileOptions)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = git.AddChanges(localPath, true); err != nil {
|
if err = git.RepoAdd(localPath, git.AddOptions{All: true}); err != nil {
|
||||||
return fmt.Errorf("git add --all: %v", err)
|
return fmt.Errorf("git add --all: %v", err)
|
||||||
} else if err = git.CommitChanges(localPath, git.CommitChangesOptions{
|
} else if err = git.RepoCommit(localPath, doer.NewGitSig(), opts.Message); err != nil {
|
||||||
Committer: doer.NewGitSig(),
|
|
||||||
Message: opts.Message,
|
|
||||||
}); err != nil {
|
|
||||||
return fmt.Errorf("commit changes on %q: %v", localPath, err)
|
return fmt.Errorf("commit changes on %q: %v", localPath, err)
|
||||||
} else if err = git.PushWithEnvs(localPath, "origin", opts.NewBranch,
|
}
|
||||||
ComposeHookEnvs(ComposeHookEnvsOptions{
|
|
||||||
|
envs := ComposeHookEnvs(ComposeHookEnvsOptions{
|
||||||
AuthUser: doer,
|
AuthUser: doer,
|
||||||
OwnerName: repo.MustOwner().Name,
|
OwnerName: repo.MustOwner().Name,
|
||||||
OwnerSalt: repo.MustOwner().Salt,
|
OwnerSalt: repo.MustOwner().Salt,
|
||||||
RepoID: repo.ID,
|
RepoID: repo.ID,
|
||||||
RepoName: repo.Name,
|
RepoName: repo.Name,
|
||||||
RepoPath: repo.RepoPath(),
|
RepoPath: repo.RepoPath(),
|
||||||
})); err != nil {
|
})
|
||||||
|
if err = git.RepoPush(localPath, "origin", opts.NewBranch, git.PushOptions{Envs: envs}); err != nil {
|
||||||
return fmt.Errorf("git push origin %s: %v", opts.NewBranch, err)
|
return fmt.Errorf("git push origin %s: %v", opts.NewBranch, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,19 +5,18 @@
|
|||||||
package db
|
package db
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"container/list"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
git "github.com/gogs/git-module"
|
"github.com/gogs/git-module"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CommitToPushCommit transforms a git.Commit to PushCommit type.
|
// CommitToPushCommit transforms a git.Commit to PushCommit type.
|
||||||
func CommitToPushCommit(commit *git.Commit) *PushCommit {
|
func CommitToPushCommit(commit *git.Commit) *PushCommit {
|
||||||
return &PushCommit{
|
return &PushCommit{
|
||||||
Sha1: commit.ID.String(),
|
Sha1: commit.ID.String(),
|
||||||
Message: commit.Message(),
|
Message: commit.Message,
|
||||||
AuthorEmail: commit.Author.Email,
|
AuthorEmail: commit.Author.Email,
|
||||||
AuthorName: commit.Author.Name,
|
AuthorName: commit.Author.Name,
|
||||||
CommitterEmail: commit.Committer.Email,
|
CommitterEmail: commit.Committer.Email,
|
||||||
@@ -26,27 +25,22 @@ func CommitToPushCommit(commit *git.Commit) *PushCommit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ListToPushCommits(l *list.List) *PushCommits {
|
func CommitsToPushCommits(commits []*git.Commit) *PushCommits {
|
||||||
if l == nil {
|
if len(commits) == 0 {
|
||||||
return &PushCommits{}
|
return &PushCommits{}
|
||||||
}
|
}
|
||||||
|
|
||||||
commits := make([]*PushCommit, 0)
|
pcs := make([]*PushCommit, len(commits))
|
||||||
var actEmail string
|
for i := range commits {
|
||||||
for e := l.Front(); e != nil; e = e.Next() {
|
pcs[i] = CommitToPushCommit(commits[i])
|
||||||
commit := e.Value.(*git.Commit)
|
|
||||||
if actEmail == "" {
|
|
||||||
actEmail = commit.Committer.Email
|
|
||||||
}
|
}
|
||||||
commits = append(commits, CommitToPushCommit(commit))
|
return &PushCommits{len(pcs), pcs, "", nil}
|
||||||
}
|
|
||||||
return &PushCommits{l.Len(), commits, "", nil}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type PushUpdateOptions struct {
|
type PushUpdateOptions struct {
|
||||||
OldCommitID string
|
OldCommitID string
|
||||||
NewCommitID string
|
NewCommitID string
|
||||||
RefFullName string
|
FullRefspec string
|
||||||
PusherID int64
|
PusherID int64
|
||||||
PusherName string
|
PusherName string
|
||||||
RepoUserName string
|
RepoUserName string
|
||||||
@@ -56,10 +50,10 @@ type PushUpdateOptions struct {
|
|||||||
// PushUpdate must be called for any push actions in order to
|
// PushUpdate must be called for any push actions in order to
|
||||||
// generates necessary push action history feeds.
|
// generates necessary push action history feeds.
|
||||||
func PushUpdate(opts PushUpdateOptions) (err error) {
|
func PushUpdate(opts PushUpdateOptions) (err error) {
|
||||||
isNewRef := opts.OldCommitID == git.EMPTY_SHA
|
isNewRef := strings.HasPrefix(opts.OldCommitID, git.EmptyID)
|
||||||
isDelRef := opts.NewCommitID == git.EMPTY_SHA
|
isDelRef := strings.HasPrefix(opts.NewCommitID, git.EmptyID)
|
||||||
if isNewRef && isDelRef {
|
if isNewRef && isDelRef {
|
||||||
return fmt.Errorf("Old and new revisions are both %s", git.EMPTY_SHA)
|
return fmt.Errorf("both old and new revisions are %q", git.EmptyID)
|
||||||
}
|
}
|
||||||
|
|
||||||
repoPath := RepoPath(opts.RepoUserName, opts.RepoName)
|
repoPath := RepoPath(opts.RepoUserName, opts.RepoName)
|
||||||
@@ -70,9 +64,9 @@ func PushUpdate(opts PushUpdateOptions) (err error) {
|
|||||||
return fmt.Errorf("run 'git update-server-info': %v", err)
|
return fmt.Errorf("run 'git update-server-info': %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
gitRepo, err := git.OpenRepository(repoPath)
|
gitRepo, err := git.Open(repoPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("OpenRepository: %v", err)
|
return fmt.Errorf("open repository: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
owner, err := GetUserByName(opts.RepoUserName)
|
owner, err := GetUserByName(opts.RepoUserName)
|
||||||
@@ -90,12 +84,12 @@ func PushUpdate(opts PushUpdateOptions) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Push tags
|
// Push tags
|
||||||
if strings.HasPrefix(opts.RefFullName, git.TAG_PREFIX) {
|
if strings.HasPrefix(opts.FullRefspec, git.RefsTags) {
|
||||||
if err := CommitRepoAction(CommitRepoActionOptions{
|
if err := CommitRepoAction(CommitRepoActionOptions{
|
||||||
PusherName: opts.PusherName,
|
PusherName: opts.PusherName,
|
||||||
RepoOwnerID: owner.ID,
|
RepoOwnerID: owner.ID,
|
||||||
RepoName: repo.Name,
|
RepoName: repo.Name,
|
||||||
RefFullName: opts.RefFullName,
|
RefFullName: opts.FullRefspec,
|
||||||
OldCommitID: opts.OldCommitID,
|
OldCommitID: opts.OldCommitID,
|
||||||
NewCommitID: opts.NewCommitID,
|
NewCommitID: opts.NewCommitID,
|
||||||
Commits: &PushCommits{},
|
Commits: &PushCommits{},
|
||||||
@@ -105,22 +99,23 @@ func PushUpdate(opts PushUpdateOptions) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var l *list.List
|
var commits []*git.Commit
|
||||||
// Skip read parent commits when delete branch
|
// Skip read parent commits when delete branch
|
||||||
if !isDelRef {
|
if !isDelRef {
|
||||||
// Push new branch
|
// Push new branch
|
||||||
newCommit, err := gitRepo.GetCommit(opts.NewCommitID)
|
newCommit, err := gitRepo.CatFileCommit(opts.NewCommitID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("GetCommit [commit_id: %s]: %v", opts.NewCommitID, err)
|
return fmt.Errorf("GetCommit [commit_id: %s]: %v", opts.NewCommitID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if isNewRef {
|
if isNewRef {
|
||||||
l, err = newCommit.CommitsBeforeLimit(10)
|
commits, err = newCommit.Ancestors(git.LogOptions{MaxCount: 9})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("CommitsBeforeLimit [commit_id: %s]: %v", newCommit.ID, err)
|
return fmt.Errorf("CommitsBeforeLimit [commit_id: %s]: %v", newCommit.ID, err)
|
||||||
}
|
}
|
||||||
|
commits = append([]*git.Commit{newCommit}, commits...)
|
||||||
} else {
|
} else {
|
||||||
l, err = newCommit.CommitsBeforeUntil(opts.OldCommitID)
|
commits, err = newCommit.CommitsAfter(opts.OldCommitID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("CommitsBeforeUntil [commit_id: %s]: %v", opts.OldCommitID, err)
|
return fmt.Errorf("CommitsBeforeUntil [commit_id: %s]: %v", opts.OldCommitID, err)
|
||||||
}
|
}
|
||||||
@@ -131,10 +126,10 @@ func PushUpdate(opts PushUpdateOptions) (err error) {
|
|||||||
PusherName: opts.PusherName,
|
PusherName: opts.PusherName,
|
||||||
RepoOwnerID: owner.ID,
|
RepoOwnerID: owner.ID,
|
||||||
RepoName: repo.Name,
|
RepoName: repo.Name,
|
||||||
RefFullName: opts.RefFullName,
|
RefFullName: opts.FullRefspec,
|
||||||
OldCommitID: opts.OldCommitID,
|
OldCommitID: opts.OldCommitID,
|
||||||
NewCommitID: opts.NewCommitID,
|
NewCommitID: opts.NewCommitID,
|
||||||
Commits: ListToPushCommits(l),
|
Commits: CommitsToPushCommits(commits),
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return fmt.Errorf("CommitRepoAction.(branch): %v", err)
|
return fmt.Errorf("CommitRepoAction.(branch): %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ package db
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"container/list"
|
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"crypto/subtle"
|
"crypto/subtle"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
@@ -977,28 +976,22 @@ func ValidateCommitWithEmail(c *git.Commit) *User {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ValidateCommitsWithEmails checks if authors' e-mails of commits are corresponding to users.
|
// ValidateCommitsWithEmails checks if authors' e-mails of commits are corresponding to users.
|
||||||
func ValidateCommitsWithEmails(oldCommits *list.List) *list.List {
|
func ValidateCommitsWithEmails(oldCommits []*git.Commit) []*UserCommit {
|
||||||
var (
|
emails := make(map[string]*User)
|
||||||
u *User
|
newCommits := make([]*UserCommit, len(oldCommits))
|
||||||
emails = map[string]*User{}
|
for i := range oldCommits {
|
||||||
newCommits = list.New()
|
var u *User
|
||||||
e = oldCommits.Front()
|
if v, ok := emails[oldCommits[i].Author.Email]; !ok {
|
||||||
)
|
u, _ = GetUserByEmail(oldCommits[i].Author.Email)
|
||||||
for e != nil {
|
emails[oldCommits[i].Author.Email] = u
|
||||||
c := e.Value.(*git.Commit)
|
|
||||||
|
|
||||||
if v, ok := emails[c.Author.Email]; !ok {
|
|
||||||
u, _ = GetUserByEmail(c.Author.Email)
|
|
||||||
emails[c.Author.Email] = u
|
|
||||||
} else {
|
} else {
|
||||||
u = v
|
u = v
|
||||||
}
|
}
|
||||||
|
|
||||||
newCommits.PushBack(UserCommit{
|
newCommits[i] = &UserCommit{
|
||||||
User: u,
|
User: u,
|
||||||
Commit: c,
|
Commit: oldCommits[i],
|
||||||
})
|
}
|
||||||
e = e.Next()
|
|
||||||
}
|
}
|
||||||
return newCommits
|
return newCommits
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ func GetDingtalkPayload(p api.Payloader, event HookEventType) (payload *Dingtalk
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getDingtalkCreatePayload(p *api.CreatePayload) (*DingtalkPayload, error) {
|
func getDingtalkCreatePayload(p *api.CreatePayload) (*DingtalkPayload, error) {
|
||||||
refName := git.RefEndName(p.Ref)
|
refName := git.RefShortName(p.Ref)
|
||||||
refType := strings.Title(p.RefType)
|
refType := strings.Title(p.RefType)
|
||||||
|
|
||||||
actionCard := NewDingtalkActionCard("View "+refType, p.Repo.HTMLURL+"/src/"+refName)
|
actionCard := NewDingtalkActionCard("View "+refType, p.Repo.HTMLURL+"/src/"+refName)
|
||||||
@@ -99,7 +99,7 @@ func getDingtalkCreatePayload(p *api.CreatePayload) (*DingtalkPayload, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getDingtalkDeletePayload(p *api.DeletePayload) (*DingtalkPayload, error) {
|
func getDingtalkDeletePayload(p *api.DeletePayload) (*DingtalkPayload, error) {
|
||||||
refName := git.RefEndName(p.Ref)
|
refName := git.RefShortName(p.Ref)
|
||||||
refType := strings.Title(p.RefType)
|
refType := strings.Title(p.RefType)
|
||||||
|
|
||||||
actionCard := NewDingtalkActionCard("View Repo", p.Repo.HTMLURL)
|
actionCard := NewDingtalkActionCard("View Repo", p.Repo.HTMLURL)
|
||||||
@@ -122,7 +122,7 @@ func getDingtalkForkPayload(p *api.ForkPayload) (*DingtalkPayload, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getDingtalkPushPayload(p *api.PushPayload) (*DingtalkPayload, error) {
|
func getDingtalkPushPayload(p *api.PushPayload) (*DingtalkPayload, error) {
|
||||||
refName := git.RefEndName(p.Ref)
|
refName := git.RefShortName(p.Ref)
|
||||||
|
|
||||||
pusher := p.Pusher.FullName
|
pusher := p.Pusher.FullName
|
||||||
if pusher == "" {
|
if pusher == "" {
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ func DiscordSHALinkFormatter(url string, text string) string {
|
|||||||
|
|
||||||
// getDiscordCreatePayload composes Discord payload for create new branch or tag.
|
// getDiscordCreatePayload composes Discord payload for create new branch or tag.
|
||||||
func getDiscordCreatePayload(p *api.CreatePayload) (*DiscordPayload, error) {
|
func getDiscordCreatePayload(p *api.CreatePayload) (*DiscordPayload, error) {
|
||||||
refName := git.RefEndName(p.Ref)
|
refName := git.RefShortName(p.Ref)
|
||||||
repoLink := DiscordLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
|
repoLink := DiscordLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
|
||||||
refLink := DiscordLinkFormatter(p.Repo.HTMLURL+"/src/"+refName, refName)
|
refLink := DiscordLinkFormatter(p.Repo.HTMLURL+"/src/"+refName, refName)
|
||||||
content := fmt.Sprintf("Created new %s: %s/%s", p.RefType, repoLink, refLink)
|
content := fmt.Sprintf("Created new %s: %s/%s", p.RefType, repoLink, refLink)
|
||||||
@@ -89,7 +89,7 @@ func getDiscordCreatePayload(p *api.CreatePayload) (*DiscordPayload, error) {
|
|||||||
|
|
||||||
// getDiscordDeletePayload composes Discord payload for delete a branch or tag.
|
// getDiscordDeletePayload composes Discord payload for delete a branch or tag.
|
||||||
func getDiscordDeletePayload(p *api.DeletePayload) (*DiscordPayload, error) {
|
func getDiscordDeletePayload(p *api.DeletePayload) (*DiscordPayload, error) {
|
||||||
refName := git.RefEndName(p.Ref)
|
refName := git.RefShortName(p.Ref)
|
||||||
repoLink := DiscordLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
|
repoLink := DiscordLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
|
||||||
content := fmt.Sprintf("Deleted %s: %s/%s", p.RefType, repoLink, refName)
|
content := fmt.Sprintf("Deleted %s: %s/%s", p.RefType, repoLink, refName)
|
||||||
return &DiscordPayload{
|
return &DiscordPayload{
|
||||||
@@ -124,7 +124,7 @@ func getDiscordForkPayload(p *api.ForkPayload) (*DiscordPayload, error) {
|
|||||||
func getDiscordPushPayload(p *api.PushPayload, slack *SlackMeta) (*DiscordPayload, error) {
|
func getDiscordPushPayload(p *api.PushPayload, slack *SlackMeta) (*DiscordPayload, error) {
|
||||||
// n new commits
|
// n new commits
|
||||||
var (
|
var (
|
||||||
branchName = git.RefEndName(p.Ref)
|
branchName = git.RefShortName(p.Ref)
|
||||||
commitDesc string
|
commitDesc string
|
||||||
commitString string
|
commitString string
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ func SlackLinkFormatter(url string, text string) string {
|
|||||||
|
|
||||||
// getSlackCreatePayload composes Slack payload for create new branch or tag.
|
// getSlackCreatePayload composes Slack payload for create new branch or tag.
|
||||||
func getSlackCreatePayload(p *api.CreatePayload) (*SlackPayload, error) {
|
func getSlackCreatePayload(p *api.CreatePayload) (*SlackPayload, error) {
|
||||||
refName := git.RefEndName(p.Ref)
|
refName := git.RefShortName(p.Ref)
|
||||||
repoLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
|
repoLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
|
||||||
refLink := SlackLinkFormatter(p.Repo.HTMLURL+"/src/"+refName, refName)
|
refLink := SlackLinkFormatter(p.Repo.HTMLURL+"/src/"+refName, refName)
|
||||||
text := fmt.Sprintf("[%s:%s] %s created by %s", repoLink, refLink, p.RefType, p.Sender.UserName)
|
text := fmt.Sprintf("[%s:%s] %s created by %s", repoLink, refLink, p.RefType, p.Sender.UserName)
|
||||||
@@ -83,7 +83,7 @@ func getSlackCreatePayload(p *api.CreatePayload) (*SlackPayload, error) {
|
|||||||
|
|
||||||
// getSlackDeletePayload composes Slack payload for delete a branch or tag.
|
// getSlackDeletePayload composes Slack payload for delete a branch or tag.
|
||||||
func getSlackDeletePayload(p *api.DeletePayload) (*SlackPayload, error) {
|
func getSlackDeletePayload(p *api.DeletePayload) (*SlackPayload, error) {
|
||||||
refName := git.RefEndName(p.Ref)
|
refName := git.RefShortName(p.Ref)
|
||||||
repoLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
|
repoLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
|
||||||
text := fmt.Sprintf("[%s:%s] %s deleted by %s", repoLink, refName, p.RefType, p.Sender.UserName)
|
text := fmt.Sprintf("[%s:%s] %s deleted by %s", repoLink, refName, p.RefType, p.Sender.UserName)
|
||||||
return &SlackPayload{
|
return &SlackPayload{
|
||||||
@@ -104,7 +104,7 @@ func getSlackForkPayload(p *api.ForkPayload) (*SlackPayload, error) {
|
|||||||
func getSlackPushPayload(p *api.PushPayload, slack *SlackMeta) (*SlackPayload, error) {
|
func getSlackPushPayload(p *api.PushPayload, slack *SlackMeta) (*SlackPayload, error) {
|
||||||
// n new commits
|
// n new commits
|
||||||
var (
|
var (
|
||||||
branchName = git.RefEndName(p.Ref)
|
branchName = git.RefShortName(p.Ref)
|
||||||
commitDesc string
|
commitDesc string
|
||||||
commitString string
|
commitString string
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -62,8 +62,8 @@ func (repo *Repository) InitWiki() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := git.InitRepository(repo.WikiPath(), true); err != nil {
|
if err := git.Init(repo.WikiPath(), git.InitOptions{Bare: true}); err != nil {
|
||||||
return fmt.Errorf("InitRepository: %v", err)
|
return fmt.Errorf("init repository: %v", err)
|
||||||
} else if err = createDelegateHooks(repo.WikiPath()); err != nil {
|
} else if err = createDelegateHooks(repo.WikiPath()); err != nil {
|
||||||
return fmt.Errorf("createDelegateHooks: %v", err)
|
return fmt.Errorf("createDelegateHooks: %v", err)
|
||||||
}
|
}
|
||||||
@@ -125,15 +125,12 @@ func (repo *Repository) updateWikiPage(doer *User, oldTitle, title, content, mes
|
|||||||
if len(message) == 0 {
|
if len(message) == 0 {
|
||||||
message = "Update page '" + title + "'"
|
message = "Update page '" + title + "'"
|
||||||
}
|
}
|
||||||
if err = git.AddChanges(localPath, true); err != nil {
|
if err = git.RepoAdd(localPath, git.AddOptions{All: true}); err != nil {
|
||||||
return fmt.Errorf("AddChanges: %v", err)
|
return fmt.Errorf("add all changes: %v", err)
|
||||||
} else if err = git.CommitChanges(localPath, git.CommitChangesOptions{
|
} else if err = git.RepoCommit(localPath, doer.NewGitSig(), message); err != nil {
|
||||||
Committer: doer.NewGitSig(),
|
return fmt.Errorf("commit changes: %v", err)
|
||||||
Message: message,
|
} else if err = git.RepoPush(localPath, "origin", "master"); err != nil {
|
||||||
}); err != nil {
|
return fmt.Errorf("push: %v", err)
|
||||||
return fmt.Errorf("CommitChanges: %v", err)
|
|
||||||
} else if err = git.Push(localPath, "origin", "master"); err != nil {
|
|
||||||
return fmt.Errorf("Push: %v", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -164,15 +161,12 @@ func (repo *Repository) DeleteWikiPage(doer *User, title string) (err error) {
|
|||||||
|
|
||||||
message := "Delete page '" + title + "'"
|
message := "Delete page '" + title + "'"
|
||||||
|
|
||||||
if err = git.AddChanges(localPath, true); err != nil {
|
if err = git.RepoAdd(localPath, git.AddOptions{All: true}); err != nil {
|
||||||
return fmt.Errorf("AddChanges: %v", err)
|
return fmt.Errorf("add all changes: %v", err)
|
||||||
} else if err = git.CommitChanges(localPath, git.CommitChangesOptions{
|
} else if err = git.RepoCommit(localPath, doer.NewGitSig(), message); err != nil {
|
||||||
Committer: doer.NewGitSig(),
|
return fmt.Errorf("commit changes: %v", err)
|
||||||
Message: message,
|
} else if err = git.RepoPush(localPath, "origin", "master"); err != nil {
|
||||||
}); err != nil {
|
return fmt.Errorf("push: %v", err)
|
||||||
return fmt.Errorf("CommitChanges: %v", err)
|
|
||||||
} else if err = git.Push(localPath, "origin", "master"); err != nil {
|
|
||||||
return fmt.Errorf("Push: %v", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
196
internal/gitutil/diff.go
Normal file
196
internal/gitutil/diff.go
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package gitutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"html"
|
||||||
|
"html/template"
|
||||||
|
"io"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/sergi/go-diff/diffmatchpatch"
|
||||||
|
"golang.org/x/net/html/charset"
|
||||||
|
"golang.org/x/text/transform"
|
||||||
|
|
||||||
|
"github.com/gogs/git-module"
|
||||||
|
|
||||||
|
"gogs.io/gogs/internal/conf"
|
||||||
|
"gogs.io/gogs/internal/template/highlight"
|
||||||
|
"gogs.io/gogs/internal/tool"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DiffSection is a wrapper to git.DiffSection with helper methods.
|
||||||
|
type DiffSection struct {
|
||||||
|
*git.DiffSection
|
||||||
|
|
||||||
|
initOnce sync.Once
|
||||||
|
dmp *diffmatchpatch.DiffMatchPatch
|
||||||
|
}
|
||||||
|
|
||||||
|
// ComputedInlineDiffFor computes inline diff for the given line.
|
||||||
|
func (s *DiffSection) ComputedInlineDiffFor(line *git.DiffLine) template.HTML {
|
||||||
|
fallback := template.HTML(html.EscapeString(line.Content))
|
||||||
|
if conf.Git.DisableDiffHighlight {
|
||||||
|
return fallback
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find equivalent diff line, ignore when not found.
|
||||||
|
var diff1, diff2 string
|
||||||
|
switch line.Type {
|
||||||
|
case git.DiffLineAdd:
|
||||||
|
compareLine := s.Line(git.DiffLineDelete, line.RightLine)
|
||||||
|
if compareLine == nil {
|
||||||
|
return fallback
|
||||||
|
}
|
||||||
|
|
||||||
|
diff1 = compareLine.Content
|
||||||
|
diff2 = line.Content
|
||||||
|
|
||||||
|
case git.DiffLineDelete:
|
||||||
|
compareLine := s.Line(git.DiffLineAdd, line.LeftLine)
|
||||||
|
if compareLine == nil {
|
||||||
|
return fallback
|
||||||
|
}
|
||||||
|
|
||||||
|
diff1 = line.Content
|
||||||
|
diff2 = compareLine.Content
|
||||||
|
|
||||||
|
default:
|
||||||
|
return fallback
|
||||||
|
}
|
||||||
|
|
||||||
|
s.initOnce.Do(func() {
|
||||||
|
s.dmp = diffmatchpatch.New()
|
||||||
|
s.dmp.DiffEditCost = 100
|
||||||
|
})
|
||||||
|
|
||||||
|
diffs := s.dmp.DiffMain(diff1[1:], diff2[1:], true)
|
||||||
|
diffs = s.dmp.DiffCleanupEfficiency(diffs)
|
||||||
|
|
||||||
|
return diffsToHTML(diffs, line.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
func diffsToHTML(diffs []diffmatchpatch.Diff, lineType git.DiffLineType) template.HTML {
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
|
||||||
|
// Reproduce signs which are cutted for inline diff before.
|
||||||
|
switch lineType {
|
||||||
|
case git.DiffLineAdd:
|
||||||
|
buf.WriteByte('+')
|
||||||
|
case git.DiffLineDelete:
|
||||||
|
buf.WriteByte('-')
|
||||||
|
}
|
||||||
|
buf.WriteByte(' ')
|
||||||
|
|
||||||
|
const (
|
||||||
|
addedCodePrefix = `<span class="added-code">`
|
||||||
|
removedCodePrefix = `<span class="removed-code">`
|
||||||
|
codeTagSuffix = `</span>`
|
||||||
|
)
|
||||||
|
|
||||||
|
for i := range diffs {
|
||||||
|
switch {
|
||||||
|
case diffs[i].Type == diffmatchpatch.DiffInsert && lineType == git.DiffLineAdd:
|
||||||
|
buf.WriteString(addedCodePrefix)
|
||||||
|
buf.WriteString(html.EscapeString(diffs[i].Text))
|
||||||
|
buf.WriteString(codeTagSuffix)
|
||||||
|
case diffs[i].Type == diffmatchpatch.DiffDelete && lineType == git.DiffLineDelete:
|
||||||
|
buf.WriteString(removedCodePrefix)
|
||||||
|
buf.WriteString(html.EscapeString(diffs[i].Text))
|
||||||
|
buf.WriteString(codeTagSuffix)
|
||||||
|
case diffs[i].Type == diffmatchpatch.DiffEqual:
|
||||||
|
buf.WriteString(html.EscapeString(diffs[i].Text))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return template.HTML(buf.Bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
// DiffFile is a wrapper to git.DiffFile with helper methods.
|
||||||
|
type DiffFile struct {
|
||||||
|
*git.DiffFile
|
||||||
|
Sections []*DiffSection
|
||||||
|
}
|
||||||
|
|
||||||
|
// HighlightClass returns the detected highlight class for the file.
|
||||||
|
func (diffFile *DiffFile) HighlightClass() string {
|
||||||
|
return highlight.FileNameToHighlightClass(diffFile.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Diff is a wrapper to git.Diff with helper methods.
|
||||||
|
type Diff struct {
|
||||||
|
*git.Diff
|
||||||
|
Files []*DiffFile
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDiff returns a new wrapper of given git.Diff.
|
||||||
|
func NewDiff(oldDiff *git.Diff) *Diff {
|
||||||
|
newDiff := &Diff{
|
||||||
|
Diff: oldDiff,
|
||||||
|
Files: make([]*DiffFile, oldDiff.NumFiles()),
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: detect encoding while parsing.
|
||||||
|
var buf bytes.Buffer
|
||||||
|
for i := range oldDiff.Files {
|
||||||
|
buf.Reset()
|
||||||
|
|
||||||
|
newDiff.Files[i] = &DiffFile{
|
||||||
|
DiffFile: oldDiff.Files[i],
|
||||||
|
Sections: make([]*DiffSection, oldDiff.Files[i].NumSections()),
|
||||||
|
}
|
||||||
|
|
||||||
|
for j := range oldDiff.Files[i].Sections {
|
||||||
|
newDiff.Files[i].Sections[j] = &DiffSection{
|
||||||
|
DiffSection: oldDiff.Files[i].Sections[j],
|
||||||
|
}
|
||||||
|
|
||||||
|
for k := range newDiff.Files[i].Sections[j].Lines {
|
||||||
|
buf.WriteString(newDiff.Files[i].Sections[j].Lines[k].Content)
|
||||||
|
buf.WriteString("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
charsetLabel, err := tool.DetectEncoding(buf.Bytes())
|
||||||
|
if charsetLabel != "UTF-8" && err == nil {
|
||||||
|
encoding, _ := charset.Lookup(charsetLabel)
|
||||||
|
if encoding != nil {
|
||||||
|
d := encoding.NewDecoder()
|
||||||
|
for j := range newDiff.Files[i].Sections {
|
||||||
|
for k := range newDiff.Files[i].Sections[j].Lines {
|
||||||
|
if c, _, err := transform.String(d, newDiff.Files[i].Sections[j].Lines[k].Content); err == nil {
|
||||||
|
newDiff.Files[i].Sections[j].Lines[k].Content = c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newDiff
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseDiff parses the diff from given io.Reader.
|
||||||
|
func ParseDiff(r io.Reader, maxFiles, maxFileLines, maxLineChars int) (*Diff, error) {
|
||||||
|
done := make(chan git.SteamParseDiffResult)
|
||||||
|
go git.StreamParseDiff(r, done, maxFiles, maxFileLines, maxLineChars)
|
||||||
|
|
||||||
|
result := <-done
|
||||||
|
if result.Err != nil {
|
||||||
|
return nil, fmt.Errorf("stream parse diff: %v", result.Err)
|
||||||
|
}
|
||||||
|
return NewDiff(result.Diff), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RepoDiff parses the diff on given revisions of given repository.
|
||||||
|
func RepoDiff(repo *git.Repository, rev string, maxFiles, maxFileLines, maxLineChars int, opts ...git.DiffOptions) (*Diff, error) {
|
||||||
|
diff, err := repo.Diff(rev, maxFiles, maxFileLines, maxLineChars, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("get diff: %v", err)
|
||||||
|
}
|
||||||
|
return NewDiff(diff), nil
|
||||||
|
}
|
||||||
49
internal/gitutil/diff_test.go
Normal file
49
internal/gitutil/diff_test.go
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
// Copyright 2016 The Gogs Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package gitutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"html/template"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
dmp "github.com/sergi/go-diff/diffmatchpatch"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"github.com/gogs/git-module"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_diffsToHTML(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
diffs []dmp.Diff
|
||||||
|
lineType git.DiffLineType
|
||||||
|
expHTML template.HTML
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
diffs: []dmp.Diff{
|
||||||
|
{Type: dmp.DiffEqual, Text: "foo "},
|
||||||
|
{Type: dmp.DiffInsert, Text: "bar"},
|
||||||
|
{Type: dmp.DiffDelete, Text: " baz"},
|
||||||
|
{Type: dmp.DiffEqual, Text: " biz"},
|
||||||
|
},
|
||||||
|
lineType: git.DiffLineAdd,
|
||||||
|
expHTML: template.HTML(`+ foo <span class="added-code">bar</span> biz`),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
diffs: []dmp.Diff{
|
||||||
|
{Type: dmp.DiffEqual, Text: "foo "},
|
||||||
|
{Type: dmp.DiffDelete, Text: "bar"},
|
||||||
|
{Type: dmp.DiffInsert, Text: " baz"},
|
||||||
|
{Type: dmp.DiffEqual, Text: " biz"},
|
||||||
|
},
|
||||||
|
lineType: git.DiffLineDelete,
|
||||||
|
expHTML: template.HTML(`- foo <span class="removed-code">bar</span> biz`),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run("", func(t *testing.T) {
|
||||||
|
assert.Equal(t, test.expHTML, diffsToHTML(test.diffs, test.lineType))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
19
internal/gitutil/error.go
Normal file
19
internal/gitutil/error.go
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
// Copyright 2020 The Gogs Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package gitutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gogs/git-module"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsErrRevisionNotExist returns true if the error is git.ErrRevisionNotExist.
|
||||||
|
func IsErrRevisionNotExist(err error) bool {
|
||||||
|
return err == git.ErrRevisionNotExist
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrNoMergeBase returns true if the error is git.ErrNoMergeBase.
|
||||||
|
func IsErrNoMergeBase(err error) bool {
|
||||||
|
return err == git.ErrNoMergeBase
|
||||||
|
}
|
||||||
23
internal/gitutil/error_test.go
Normal file
23
internal/gitutil/error_test.go
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
// Copyright 2020 The Gogs Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package gitutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/gogs/git-module"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIsErrRevisionNotExist(t *testing.T) {
|
||||||
|
assert.True(t, IsErrRevisionNotExist(git.ErrRevisionNotExist))
|
||||||
|
assert.False(t, IsErrRevisionNotExist(os.ErrNotExist))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsErrNoMergeBase(t *testing.T) {
|
||||||
|
assert.True(t, IsErrNoMergeBase(git.ErrNoMergeBase))
|
||||||
|
assert.False(t, IsErrNoMergeBase(os.ErrNotExist))
|
||||||
|
}
|
||||||
23
internal/gitutil/mock.go
Normal file
23
internal/gitutil/mock.go
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
// Copyright 2020 The Gogs Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package gitutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gogs/git-module"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MockModuleStore struct {
|
||||||
|
RepoAddRemote func(repoPath, name, url string, opts ...git.AddRemoteOptions) error
|
||||||
|
RepoDiffNameOnly func(repoPath, base, head string, opts ...git.DiffNameOnlyOptions) ([]string, error)
|
||||||
|
RepoLog func(repoPath, rev string, opts ...git.LogOptions) ([]*git.Commit, error)
|
||||||
|
RepoMergeBase func(repoPath, base, head string, opts ...git.MergeBaseOptions) (string, error)
|
||||||
|
RepoRemoveRemote func(repoPath, name string, opts ...git.RemoveRemoteOptions) error
|
||||||
|
RepoTags func(repoPath string, opts ...git.TagsOptions) ([]string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MockModule holds mock implementation of each method for Modulers interface.
|
||||||
|
// When the field is non-nil, it is considered mocked. Otherwise, the real
|
||||||
|
// implementation will be executed.
|
||||||
|
var MockModule MockModuleStore
|
||||||
90
internal/gitutil/module.go
Normal file
90
internal/gitutil/module.go
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
// Copyright 2020 The Gogs Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package gitutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gogs/git-module"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Moduler is the interface for Git operations.
|
||||||
|
//
|
||||||
|
// NOTE: All methods are sorted in alphabetically.
|
||||||
|
type Moduler interface {
|
||||||
|
// AddRemote adds a new remote to the repository in given path.
|
||||||
|
RepoAddRemote(repoPath, name, url string, opts ...git.AddRemoteOptions) error
|
||||||
|
// RepoDiffNameOnly returns a list of changed files between base and head revisions
|
||||||
|
// of the repository in given path.
|
||||||
|
RepoDiffNameOnly(repoPath, base, head string, opts ...git.DiffNameOnlyOptions) ([]string, error)
|
||||||
|
// RepoLog returns a list of commits in the state of given revision of the repository
|
||||||
|
// in given path. The returned list is in reverse chronological order.
|
||||||
|
RepoLog(repoPath, rev string, opts ...git.LogOptions) ([]*git.Commit, error)
|
||||||
|
// RepoMergeBase returns merge base between base and head revisions of the repository
|
||||||
|
// in given path.
|
||||||
|
RepoMergeBase(repoPath, base, head string, opts ...git.MergeBaseOptions) (string, error)
|
||||||
|
// RepoRemoveRemote removes a remote from the repository in given path.
|
||||||
|
RepoRemoveRemote(repoPath, name string, opts ...git.RemoveRemoteOptions) error
|
||||||
|
// RepoTags returns a list of tags of the repository in given path.
|
||||||
|
RepoTags(repoPath string, opts ...git.TagsOptions) ([]string, error)
|
||||||
|
|
||||||
|
Utiler
|
||||||
|
}
|
||||||
|
|
||||||
|
// Utiler is the interface for utility helpers implemented in this package.
|
||||||
|
//
|
||||||
|
// NOTE: All methods are sorted in alphabetically.
|
||||||
|
type Utiler interface {
|
||||||
|
// GetPullRequestMeta gathers pull request metadata based on given head and base information.
|
||||||
|
PullRequestMeta(headPath, basePath, headBranch, baseBranch string) (*PullRequestMeta, error)
|
||||||
|
// ListTagsAfter returns a list of tags "after" (exlusive) given tag.
|
||||||
|
ListTagsAfter(repoPath, after string, limit int) (*TagsPage, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// moduler is holds real implementation.
|
||||||
|
type moduler struct{}
|
||||||
|
|
||||||
|
func (moduler) RepoAddRemote(repoPath, name, url string, opts ...git.AddRemoteOptions) error {
|
||||||
|
if MockModule.RepoAddRemote != nil {
|
||||||
|
return MockModule.RepoAddRemote(repoPath, name, url, opts...)
|
||||||
|
}
|
||||||
|
return git.RepoAddRemote(repoPath, name, url, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (moduler) RepoDiffNameOnly(repoPath, base, head string, opts ...git.DiffNameOnlyOptions) ([]string, error) {
|
||||||
|
if MockModule.RepoDiffNameOnly != nil {
|
||||||
|
return MockModule.RepoDiffNameOnly(repoPath, base, head, opts...)
|
||||||
|
}
|
||||||
|
return git.RepoDiffNameOnly(repoPath, base, head, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (moduler) RepoLog(repoPath, rev string, opts ...git.LogOptions) ([]*git.Commit, error) {
|
||||||
|
if MockModule.RepoLog != nil {
|
||||||
|
return MockModule.RepoLog(repoPath, rev, opts...)
|
||||||
|
}
|
||||||
|
return git.RepoLog(repoPath, rev, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (moduler) RepoMergeBase(repoPath, base, head string, opts ...git.MergeBaseOptions) (string, error) {
|
||||||
|
if MockModule.RepoMergeBase != nil {
|
||||||
|
return MockModule.RepoMergeBase(repoPath, base, head, opts...)
|
||||||
|
}
|
||||||
|
return git.RepoMergeBase(repoPath, base, head, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (moduler) RepoRemoveRemote(repoPath, name string, opts ...git.RemoveRemoteOptions) error {
|
||||||
|
if MockModule.RepoRemoveRemote != nil {
|
||||||
|
return MockModule.RepoRemoveRemote(repoPath, name, opts...)
|
||||||
|
}
|
||||||
|
return git.RepoRemoveRemote(repoPath, name, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (moduler) RepoTags(repoPath string, opts ...git.TagsOptions) ([]string, error) {
|
||||||
|
if MockModule.RepoTags != nil {
|
||||||
|
return MockModule.RepoTags(repoPath, opts...)
|
||||||
|
}
|
||||||
|
return git.RepoTags(repoPath, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Module is a mockable interface for Git operations.
|
||||||
|
var Module Moduler = moduler{}
|
||||||
69
internal/gitutil/pull_request.go
Normal file
69
internal/gitutil/pull_request.go
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
// Copyright 2020 The Gogs Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package gitutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gogs/git-module"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
log "unknwon.dev/clog/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PullRequestMeta contains metadata for a pull request.
|
||||||
|
type PullRequestMeta struct {
|
||||||
|
// The merge base of the pull request.
|
||||||
|
MergeBase string
|
||||||
|
// The commits that are requested to be merged.
|
||||||
|
Commits []*git.Commit
|
||||||
|
// The number of files changed.
|
||||||
|
NumFiles int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (moduler) PullRequestMeta(headPath, basePath, headBranch, baseBranch string) (*PullRequestMeta, error) {
|
||||||
|
tmpRemoteBranch := baseBranch
|
||||||
|
|
||||||
|
// We need to create a temporary remote when the pull request is sent from a forked repository.
|
||||||
|
if headPath != basePath {
|
||||||
|
tmpRemote := strconv.FormatInt(time.Now().UnixNano(), 10)
|
||||||
|
err := Module.RepoAddRemote(headPath, tmpRemote, basePath, git.AddRemoteOptions{Fetch: true})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("add remote: %v", err)
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
err := Module.RepoRemoveRemote(headPath, tmpRemote)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to remove remote %q [path: %s]: %v", tmpRemote, headPath, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
tmpRemoteBranch = "remotes/" + tmpRemote + "/" + baseBranch
|
||||||
|
}
|
||||||
|
|
||||||
|
mergeBase, err := Module.RepoMergeBase(headPath, tmpRemoteBranch, headBranch)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "get merge base")
|
||||||
|
}
|
||||||
|
|
||||||
|
commits, err := Module.RepoLog(headPath, mergeBase+"..."+headBranch)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "get commits")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count number of changed files
|
||||||
|
names, err := Module.RepoDiffNameOnly(headPath, tmpRemoteBranch, headBranch, git.DiffNameOnlyOptions{NeedsMergeBase: true})
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "get changed files")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &PullRequestMeta{
|
||||||
|
MergeBase: mergeBase,
|
||||||
|
Commits: commits,
|
||||||
|
NumFiles: len(names),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
108
internal/gitutil/pull_request_test.go
Normal file
108
internal/gitutil/pull_request_test.go
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
// Copyright 2020 The Gogs Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package gitutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/gogs/git-module"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestModuler_PullRequestMeta(t *testing.T) {
|
||||||
|
headPath := "/head/path"
|
||||||
|
basePath := "/base/path"
|
||||||
|
headBranch := "head_branch"
|
||||||
|
baseBranch := "base_branch"
|
||||||
|
mergeBase := "MERGE-BASE"
|
||||||
|
changedFiles := []string{"a.go", "b.txt"}
|
||||||
|
commits := []*git.Commit{
|
||||||
|
{ID: git.MustIDFromString("adfd6da3c0a3fb038393144becbf37f14f780087")},
|
||||||
|
}
|
||||||
|
|
||||||
|
MockModule.RepoAddRemote = func(repoPath, name, url string, opts ...git.AddRemoteOptions) error {
|
||||||
|
if repoPath != headPath {
|
||||||
|
return fmt.Errorf("repoPath: want %q but got %q", headPath, repoPath)
|
||||||
|
} else if name == "" {
|
||||||
|
return errors.New("empty name")
|
||||||
|
} else if url != basePath {
|
||||||
|
return fmt.Errorf("url: want %q but got %q", basePath, url)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(opts) == 0 {
|
||||||
|
return errors.New("no options")
|
||||||
|
} else if !opts[0].Fetch {
|
||||||
|
return fmt.Errorf("opts.Fetch: want %v but got %v", true, opts[0].Fetch)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
MockModule.RepoMergeBase = func(repoPath, base, head string, opts ...git.MergeBaseOptions) (string, error) {
|
||||||
|
if repoPath != headPath {
|
||||||
|
return "", fmt.Errorf("repoPath: want %q but got %q", headPath, repoPath)
|
||||||
|
} else if base == "" {
|
||||||
|
return "", errors.New("empty base")
|
||||||
|
} else if head != headBranch {
|
||||||
|
return "", fmt.Errorf("head: want %q but got %q", headBranch, head)
|
||||||
|
}
|
||||||
|
|
||||||
|
return mergeBase, nil
|
||||||
|
}
|
||||||
|
MockModule.RepoLog = func(repoPath, rev string, opts ...git.LogOptions) ([]*git.Commit, error) {
|
||||||
|
if repoPath != headPath {
|
||||||
|
return nil, fmt.Errorf("repoPath: want %q but got %q", headPath, repoPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
expRev := mergeBase + "..." + headBranch
|
||||||
|
if rev != expRev {
|
||||||
|
return nil, fmt.Errorf("rev: want %q but got %q", expRev, rev)
|
||||||
|
}
|
||||||
|
|
||||||
|
return commits, nil
|
||||||
|
}
|
||||||
|
MockModule.RepoDiffNameOnly = func(repoPath, base, head string, opts ...git.DiffNameOnlyOptions) ([]string, error) {
|
||||||
|
if repoPath != headPath {
|
||||||
|
return nil, fmt.Errorf("repoPath: want %q but got %q", headPath, repoPath)
|
||||||
|
} else if base == "" {
|
||||||
|
return nil, errors.New("empty base")
|
||||||
|
} else if head != headBranch {
|
||||||
|
return nil, fmt.Errorf("head: want %q but got %q", headBranch, head)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(opts) == 0 {
|
||||||
|
return nil, errors.New("no options")
|
||||||
|
} else if !opts[0].NeedsMergeBase {
|
||||||
|
return nil, fmt.Errorf("opts.NeedsMergeBase: want %v but got %v", true, opts[0].NeedsMergeBase)
|
||||||
|
}
|
||||||
|
|
||||||
|
return changedFiles, nil
|
||||||
|
}
|
||||||
|
MockModule.RepoRemoveRemote = func(repoPath, name string, opts ...git.RemoveRemoteOptions) error {
|
||||||
|
if repoPath != headPath {
|
||||||
|
return fmt.Errorf("repoPath: want %q but got %q", headPath, repoPath)
|
||||||
|
} else if name == "" {
|
||||||
|
return errors.New("empty name")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
MockModule = MockModuleStore{}
|
||||||
|
}()
|
||||||
|
|
||||||
|
meta, err := Module.PullRequestMeta(headPath, basePath, headBranch, baseBranch)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expMeta := &PullRequestMeta{
|
||||||
|
MergeBase: mergeBase,
|
||||||
|
Commits: commits,
|
||||||
|
NumFiles: 2,
|
||||||
|
}
|
||||||
|
assert.Equal(t, expMeta, meta)
|
||||||
|
}
|
||||||
48
internal/gitutil/submodule.go
Normal file
48
internal/gitutil/submodule.go
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
// Copyright 2020 The Gogs Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package gitutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gogs/git-module"
|
||||||
|
|
||||||
|
"gogs.io/gogs/internal/lazyregexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
var scpSyntax = lazyregexp.New(`^([a-zA-Z0-9_]+@)?([a-zA-Z0-9._-]+):(.*)$`)
|
||||||
|
|
||||||
|
// InferSubmoduleURL returns the inferred external URL of the submodule at best effort.
|
||||||
|
func InferSubmoduleURL(mod *git.Submodule) string {
|
||||||
|
raw := strings.TrimSuffix(mod.URL, "/")
|
||||||
|
raw = strings.TrimSuffix(raw, ".git")
|
||||||
|
|
||||||
|
parsed, err := url.Parse(raw)
|
||||||
|
if err != nil {
|
||||||
|
// Try parse as SCP syntax again
|
||||||
|
match := scpSyntax.FindAllStringSubmatch(raw, -1)
|
||||||
|
if len(match) == 0 {
|
||||||
|
return mod.URL
|
||||||
|
}
|
||||||
|
parsed = &url.URL{
|
||||||
|
Scheme: "http",
|
||||||
|
Host: match[0][2],
|
||||||
|
Path: match[0][3],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch parsed.Scheme {
|
||||||
|
case "http", "https":
|
||||||
|
raw = parsed.String()
|
||||||
|
case "ssh":
|
||||||
|
raw = fmt.Sprintf("http://%s%s", parsed.Host, parsed.Path)
|
||||||
|
default:
|
||||||
|
return raw
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("%s/commit/%s", raw, mod.Commit)
|
||||||
|
}
|
||||||
58
internal/gitutil/submodule_test.go
Normal file
58
internal/gitutil/submodule_test.go
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
// Copyright 2020 The Gogs Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package gitutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/gogs/git-module"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestInferSubmoduleURL(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
submodule *git.Submodule
|
||||||
|
expURL string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "HTTPS URL",
|
||||||
|
submodule: &git.Submodule{
|
||||||
|
URL: "https://github.com/gogs/docs-api.git",
|
||||||
|
Commit: "6b08f76a5313fa3d26859515b30aa17a5faa2807",
|
||||||
|
},
|
||||||
|
expURL: "https://github.com/gogs/docs-api/commit/6b08f76a5313fa3d26859515b30aa17a5faa2807",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "SSH URL with port",
|
||||||
|
submodule: &git.Submodule{
|
||||||
|
URL: "ssh://user@github.com:22/gogs/docs-api.git",
|
||||||
|
Commit: "6b08f76a5313fa3d26859515b30aa17a5faa2807",
|
||||||
|
},
|
||||||
|
expURL: "http://github.com:22/gogs/docs-api/commit/6b08f76a5313fa3d26859515b30aa17a5faa2807",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "SSH URL in SCP syntax",
|
||||||
|
submodule: &git.Submodule{
|
||||||
|
URL: "git@github.com:gogs/docs-api.git",
|
||||||
|
Commit: "6b08f76a5313fa3d26859515b30aa17a5faa2807",
|
||||||
|
},
|
||||||
|
expURL: "http://github.com/gogs/docs-api/commit/6b08f76a5313fa3d26859515b30aa17a5faa2807",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "bad URL",
|
||||||
|
submodule: &git.Submodule{
|
||||||
|
URL: "ftp://example.com",
|
||||||
|
Commit: "6b08f76a5313fa3d26859515b30aa17a5faa2807",
|
||||||
|
},
|
||||||
|
expURL: "ftp://example.com",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
assert.Equal(t, test.expURL, InferSubmoduleURL(test.submodule))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
95
internal/gitutil/tag.go
Normal file
95
internal/gitutil/tag.go
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
// Copyright 2020 The Gogs Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package gitutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TagsPage contains a list of tags and pagination information.
|
||||||
|
type TagsPage struct {
|
||||||
|
// List of tags in the current page.
|
||||||
|
Tags []string
|
||||||
|
// Whether the results include the latest tag.
|
||||||
|
HasLatest bool
|
||||||
|
// When results do not include the latest tag, an indicator of 'after' to go back.
|
||||||
|
PreviousAfter string
|
||||||
|
// Whether there are more tags in the next page.
|
||||||
|
HasNext bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (moduler) ListTagsAfter(repoPath, after string, limit int) (*TagsPage, error) {
|
||||||
|
all, err := Module.RepoTags(repoPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "get tags")
|
||||||
|
}
|
||||||
|
total := len(all)
|
||||||
|
|
||||||
|
if limit < 0 {
|
||||||
|
limit = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns everything when no filter and no limit
|
||||||
|
if after == "" && limit == 0 {
|
||||||
|
return &TagsPage{
|
||||||
|
Tags: all,
|
||||||
|
HasLatest: true,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// No filter but has a limit, returns first X tags
|
||||||
|
if after == "" && limit > 0 {
|
||||||
|
endIdx := limit
|
||||||
|
if limit > total {
|
||||||
|
endIdx = total
|
||||||
|
}
|
||||||
|
return &TagsPage{
|
||||||
|
Tags: all[:endIdx],
|
||||||
|
HasLatest: true,
|
||||||
|
HasNext: limit < total,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop over all tags see if we can find the filter
|
||||||
|
previousAfter := ""
|
||||||
|
found := false
|
||||||
|
tags := make([]string, 0, len(all))
|
||||||
|
for i := range all {
|
||||||
|
if all[i] != after {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
found = true
|
||||||
|
if limit > 0 && i-limit >= 0 {
|
||||||
|
previousAfter = all[i-limit]
|
||||||
|
}
|
||||||
|
|
||||||
|
// In case filter is the oldest one
|
||||||
|
if i+1 < total {
|
||||||
|
tags = all[i+1:]
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
tags = all
|
||||||
|
}
|
||||||
|
|
||||||
|
// If all tags after match is equal to the limit, it reaches the oldest tag as well.
|
||||||
|
if limit == 0 || len(tags) <= limit {
|
||||||
|
return &TagsPage{
|
||||||
|
Tags: tags,
|
||||||
|
HasLatest: !found,
|
||||||
|
PreviousAfter: previousAfter,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &TagsPage{
|
||||||
|
Tags: tags[:limit],
|
||||||
|
HasLatest: !found,
|
||||||
|
PreviousAfter: previousAfter,
|
||||||
|
HasNext: true,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
109
internal/gitutil/tag_test.go
Normal file
109
internal/gitutil/tag_test.go
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
// Copyright 2020 The Gogs Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package gitutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/gogs/git-module"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestModuler_ListTagsAfter(t *testing.T) {
|
||||||
|
MockModule.RepoTags = func(string, ...git.TagsOptions) ([]string, error) {
|
||||||
|
return []string{
|
||||||
|
"v2.3.0", "v2.2.1", "v2.1.0",
|
||||||
|
"v1.3.0", "v1.2.0", "v1.1.0",
|
||||||
|
"v0.8.0", "v0.5.0", "v0.1.0",
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
MockModule = MockModuleStore{}
|
||||||
|
}()
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
after string
|
||||||
|
expTagsPage *TagsPage
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "first page",
|
||||||
|
expTagsPage: &TagsPage{
|
||||||
|
Tags: []string{
|
||||||
|
"v2.3.0", "v2.2.1", "v2.1.0",
|
||||||
|
},
|
||||||
|
HasLatest: true,
|
||||||
|
HasNext: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "second page",
|
||||||
|
after: "v2.1.0",
|
||||||
|
expTagsPage: &TagsPage{
|
||||||
|
Tags: []string{
|
||||||
|
"v1.3.0", "v1.2.0", "v1.1.0",
|
||||||
|
},
|
||||||
|
HasLatest: false,
|
||||||
|
HasNext: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "last page",
|
||||||
|
after: "v1.1.0",
|
||||||
|
expTagsPage: &TagsPage{
|
||||||
|
Tags: []string{
|
||||||
|
"v0.8.0", "v0.5.0", "v0.1.0",
|
||||||
|
},
|
||||||
|
HasLatest: false,
|
||||||
|
PreviousAfter: "v2.1.0",
|
||||||
|
HasNext: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: "arbitrary after",
|
||||||
|
after: "v1.2.0",
|
||||||
|
expTagsPage: &TagsPage{
|
||||||
|
Tags: []string{
|
||||||
|
"v1.1.0", "v0.8.0", "v0.5.0",
|
||||||
|
},
|
||||||
|
HasLatest: false,
|
||||||
|
PreviousAfter: "v2.2.1",
|
||||||
|
HasNext: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "after the oldest one",
|
||||||
|
after: "v0.1.0",
|
||||||
|
expTagsPage: &TagsPage{
|
||||||
|
Tags: []string{},
|
||||||
|
HasLatest: false,
|
||||||
|
PreviousAfter: "v1.1.0",
|
||||||
|
HasNext: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "after does not exist",
|
||||||
|
after: "v2.2.9",
|
||||||
|
expTagsPage: &TagsPage{
|
||||||
|
Tags: []string{
|
||||||
|
"v2.3.0", "v2.2.1", "v2.1.0",
|
||||||
|
},
|
||||||
|
HasLatest: true,
|
||||||
|
HasNext: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
tagsPage, err := Module.ListTagsAfter("", test.after, 3)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, test.expTagsPage, tagsPage)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -43,7 +43,7 @@ func ToCommit(c *git.Commit) *api.PayloadCommit {
|
|||||||
}
|
}
|
||||||
return &api.PayloadCommit{
|
return &api.PayloadCommit{
|
||||||
ID: c.ID.String(),
|
ID: c.ID.String(),
|
||||||
Message: c.Message(),
|
Message: c.Message,
|
||||||
URL: "Not implemented",
|
URL: "Not implemented",
|
||||||
Author: &api.PayloadUser{
|
Author: &api.PayloadUser{
|
||||||
Name: c.Author.Name,
|
Name: c.Author.Name,
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import (
|
|||||||
"gogs.io/gogs/internal/context"
|
"gogs.io/gogs/internal/context"
|
||||||
"gogs.io/gogs/internal/db"
|
"gogs.io/gogs/internal/db"
|
||||||
"gogs.io/gogs/internal/db/errors"
|
"gogs.io/gogs/internal/db/errors"
|
||||||
|
"gogs.io/gogs/internal/gitutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetSingleCommit(c *context.APIContext) {
|
func GetSingleCommit(c *context.APIContext) {
|
||||||
@@ -25,14 +26,14 @@ func GetSingleCommit(c *context.APIContext) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
gitRepo, err := git.OpenRepository(c.Repo.Repository.RepoPath())
|
gitRepo, err := git.Open(c.Repo.Repository.RepoPath())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ServerError("OpenRepository", err)
|
c.ServerError("open repository", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
commit, err := gitRepo.GetCommit(c.Params(":sha"))
|
commit, err := gitRepo.CatFileCommit(c.Params(":sha"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.NotFoundOrServerError("GetCommit", git.IsErrNotExist, err)
|
c.NotFoundOrServerError("get commit", gitutil.IsErrRevisionNotExist, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,8 +60,8 @@ func GetSingleCommit(c *context.APIContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve parent(s) of the commit
|
// Retrieve parent(s) of the commit
|
||||||
apiParents := make([]*api.CommitMeta, commit.ParentCount())
|
apiParents := make([]*api.CommitMeta, commit.ParentsCount())
|
||||||
for i := 0; i < commit.ParentCount(); i++ {
|
for i := 0; i < commit.ParentsCount(); i++ {
|
||||||
sha, _ := commit.ParentID(i)
|
sha, _ := commit.ParentID(i)
|
||||||
apiParents[i] = &api.CommitMeta{
|
apiParents[i] = &api.CommitMeta{
|
||||||
URL: c.BaseURL + "/repos/" + c.Repo.Repository.FullName() + "/commits/" + sha.String(),
|
URL: c.BaseURL + "/repos/" + c.Repo.Repository.FullName() + "/commits/" + sha.String(),
|
||||||
@@ -99,24 +100,24 @@ func GetSingleCommit(c *context.APIContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetReferenceSHA(c *context.APIContext) {
|
func GetReferenceSHA(c *context.APIContext) {
|
||||||
gitRepo, err := git.OpenRepository(c.Repo.Repository.RepoPath())
|
gitRepo, err := git.Open(c.Repo.Repository.RepoPath())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ServerError("OpenRepository", err)
|
c.ServerError("open repository", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ref := c.Params("*")
|
ref := c.Params("*")
|
||||||
refType := 0 // 0-undetermined, 1-branch, 2-tag
|
refType := 0 // 0-unknown, 1-branch, 2-tag
|
||||||
if strings.HasPrefix(ref, git.BRANCH_PREFIX) {
|
if strings.HasPrefix(ref, git.RefsHeads) {
|
||||||
ref = strings.TrimPrefix(ref, git.BRANCH_PREFIX)
|
ref = strings.TrimPrefix(ref, git.RefsHeads)
|
||||||
refType = 1
|
refType = 1
|
||||||
} else if strings.HasPrefix(ref, git.TAG_PREFIX) {
|
} else if strings.HasPrefix(ref, git.RefsTags) {
|
||||||
ref = strings.TrimPrefix(ref, git.TAG_PREFIX)
|
ref = strings.TrimPrefix(ref, git.RefsTags)
|
||||||
refType = 2
|
refType = 2
|
||||||
} else {
|
} else {
|
||||||
if gitRepo.IsBranchExist(ref) {
|
if gitRepo.HasBranch(ref) {
|
||||||
refType = 1
|
refType = 1
|
||||||
} else if gitRepo.IsTagExist(ref) {
|
} else if gitRepo.HasTag(ref) {
|
||||||
refType = 2
|
refType = 2
|
||||||
} else {
|
} else {
|
||||||
c.NotFound()
|
c.NotFound()
|
||||||
@@ -126,12 +127,12 @@ func GetReferenceSHA(c *context.APIContext) {
|
|||||||
|
|
||||||
var sha string
|
var sha string
|
||||||
if refType == 1 {
|
if refType == 1 {
|
||||||
sha, err = gitRepo.GetBranchCommitID(ref)
|
sha, err = gitRepo.BranchCommitID(ref)
|
||||||
} else if refType == 2 {
|
} else if refType == 2 {
|
||||||
sha, err = gitRepo.GetTagCommitID(ref)
|
sha, err = gitRepo.TagCommitID(ref)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.NotFoundOrServerError("get reference commit ID", git.IsErrNotExist, err)
|
c.NotFoundOrServerError("get reference commit ID", gitutil.IsErrRevisionNotExist, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.PlainText(http.StatusOK, []byte(sha))
|
c.PlainText(http.StatusOK, []byte(sha))
|
||||||
|
|||||||
@@ -7,11 +7,9 @@ package repo
|
|||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
|
|
||||||
"github.com/gogs/git-module"
|
|
||||||
|
|
||||||
"gogs.io/gogs/internal/context"
|
"gogs.io/gogs/internal/context"
|
||||||
|
"gogs.io/gogs/internal/gitutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
type repoContent struct {
|
type repoContent struct {
|
||||||
@@ -38,9 +36,9 @@ type Links struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetContents(c *context.APIContext) {
|
func GetContents(c *context.APIContext) {
|
||||||
treeEntry, err := c.Repo.Commit.GetTreeEntryByPath(c.Repo.TreePath)
|
treeEntry, err := c.Repo.Commit.TreeEntry(c.Repo.TreePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.NotFoundOrServerError("GetTreeEntryByPath", git.IsErrNotExist, err)
|
c.NotFoundOrServerError("get tree entry", gitutil.IsErrRevisionNotExist, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
username := c.Params(":username")
|
username := c.Params(":username")
|
||||||
@@ -56,8 +54,8 @@ func GetContents(c *context.APIContext) {
|
|||||||
// :baseurl/repos/:username/:project/tree/:sha
|
// :baseurl/repos/:username/:project/tree/:sha
|
||||||
templateHTMLLLink := "%s/repos/%s/%s/tree/%s"
|
templateHTMLLLink := "%s/repos/%s/%s/tree/%s"
|
||||||
|
|
||||||
gitURL := fmt.Sprintf(templateGitURLLink, c.BaseURL, username, reponame, treeEntry.ID.String())
|
gitURL := fmt.Sprintf(templateGitURLLink, c.BaseURL, username, reponame, treeEntry.ID().String())
|
||||||
htmlURL := fmt.Sprintf(templateHTMLLLink, c.BaseURL, username, reponame, treeEntry.ID.String())
|
htmlURL := fmt.Sprintf(templateHTMLLLink, c.BaseURL, username, reponame, treeEntry.ID().String())
|
||||||
selfURL := fmt.Sprintf(templateSelfLink, c.BaseURL, username, reponame, c.Repo.TreePath)
|
selfURL := fmt.Sprintf(templateSelfLink, c.BaseURL, username, reponame, c.Repo.TreePath)
|
||||||
|
|
||||||
// TODO(unknwon): Make a treeEntryToRepoContent helper.
|
// TODO(unknwon): Make a treeEntryToRepoContent helper.
|
||||||
@@ -65,7 +63,7 @@ func GetContents(c *context.APIContext) {
|
|||||||
Size: treeEntry.Size(),
|
Size: treeEntry.Size(),
|
||||||
Name: treeEntry.Name(),
|
Name: treeEntry.Name(),
|
||||||
Path: c.Repo.TreePath,
|
Path: c.Repo.TreePath,
|
||||||
Sha: treeEntry.ID.String(),
|
Sha: treeEntry.ID().String(),
|
||||||
URL: selfURL,
|
URL: selfURL,
|
||||||
GitURL: gitURL,
|
GitURL: gitURL,
|
||||||
HTMLURL: htmlURL,
|
HTMLURL: htmlURL,
|
||||||
@@ -82,65 +80,57 @@ func GetContents(c *context.APIContext) {
|
|||||||
// 2. SubModule
|
// 2. SubModule
|
||||||
// 3. SymLink
|
// 3. SymLink
|
||||||
// 4. Blob (file)
|
// 4. Blob (file)
|
||||||
if treeEntry.IsSubModule() {
|
if treeEntry.IsCommit() {
|
||||||
// TODO(unknwon): submoduleURL is not set as current git-module doesn't handle it properly
|
// TODO(unknwon): submoduleURL is not set as current git-module doesn't handle it properly
|
||||||
contents.Type = "submodule"
|
contents.Type = "submodule"
|
||||||
c.JSONSuccess(contents)
|
c.JSONSuccess(contents)
|
||||||
return
|
return
|
||||||
|
|
||||||
} else if treeEntry.IsLink() {
|
} else if treeEntry.IsSymlink() {
|
||||||
contents.Type = "symlink"
|
contents.Type = "symlink"
|
||||||
blob, err := c.Repo.Commit.GetBlobByPath(c.Repo.TreePath)
|
blob, err := c.Repo.Commit.Blob(c.Repo.TreePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ServerError("GetBlobByPath", err)
|
c.ServerError("GetBlobByPath", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
b, err := blob.Data()
|
p, err := blob.Bytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ServerError("Data", err)
|
c.ServerError("Data", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
buf, err := ioutil.ReadAll(b)
|
contents.Target = string(p)
|
||||||
if err != nil {
|
|
||||||
c.ServerError("ReadAll", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
contents.Target = string(buf)
|
|
||||||
c.JSONSuccess(contents)
|
c.JSONSuccess(contents)
|
||||||
return
|
return
|
||||||
|
|
||||||
} else if treeEntry.Type == "blob" {
|
} else if treeEntry.IsBlob() {
|
||||||
blob, err := c.Repo.Commit.GetBlobByPath(c.Repo.TreePath)
|
blob, err := c.Repo.Commit.Blob(c.Repo.TreePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ServerError("GetBlobByPath", err)
|
c.ServerError("GetBlobByPath", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
b, err := blob.Data()
|
p, err := blob.Bytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ServerError("Data", err)
|
c.ServerError("Data", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
buf, err := ioutil.ReadAll(b)
|
contents.Content = base64.StdEncoding.EncodeToString(p)
|
||||||
if err != nil {
|
|
||||||
c.ServerError("ReadAll", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
contents.Content = base64.StdEncoding.EncodeToString(buf)
|
|
||||||
contents.Type = "file"
|
contents.Type = "file"
|
||||||
c.JSONSuccess(contents)
|
c.JSONSuccess(contents)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: treeEntry.IsExec()
|
||||||
|
|
||||||
// treeEntry is a directory
|
// treeEntry is a directory
|
||||||
dirTree, err := c.Repo.GitRepo.GetTree(treeEntry.ID.String())
|
dirTree, err := c.Repo.GitRepo.LsTree(treeEntry.ID().String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.NotFoundOrServerError("GetTree", git.IsErrNotExist, err)
|
c.NotFoundOrServerError("get tree", gitutil.IsErrRevisionNotExist, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
entries, err := dirTree.ListEntries()
|
entries, err := dirTree.Entries()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.NotFoundOrServerError("ListEntries", git.IsErrNotExist, err)
|
c.NotFoundOrServerError("list entries", gitutil.IsErrRevisionNotExist, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,33 +141,28 @@ func GetContents(c *context.APIContext) {
|
|||||||
|
|
||||||
var results = make([]*repoContent, 0, len(entries))
|
var results = make([]*repoContent, 0, len(entries))
|
||||||
for _, entry := range entries {
|
for _, entry := range entries {
|
||||||
gitURL := fmt.Sprintf(templateGitURLLink, c.BaseURL, username, reponame, entry.ID.String())
|
gitURL := fmt.Sprintf(templateGitURLLink, c.BaseURL, username, reponame, entry.ID().String())
|
||||||
htmlURL := fmt.Sprintf(templateHTMLLLink, c.BaseURL, username, reponame, entry.ID.String())
|
htmlURL := fmt.Sprintf(templateHTMLLLink, c.BaseURL, username, reponame, entry.ID().String())
|
||||||
selfURL := fmt.Sprintf(templateSelfLink, c.BaseURL, username, reponame, c.Repo.TreePath)
|
selfURL := fmt.Sprintf(templateSelfLink, c.BaseURL, username, reponame, c.Repo.TreePath)
|
||||||
var contentType string
|
var contentType string
|
||||||
if entry.IsDir() {
|
if entry.IsTree() {
|
||||||
contentType = "dir"
|
contentType = "dir"
|
||||||
} else if entry.IsSubModule() {
|
} else if entry.IsCommit() {
|
||||||
// TODO(unknwon): submoduleURL is not set as current git-module doesn't handle it properly
|
// TODO(unknwon): submoduleURL is not set as current git-module doesn't handle it properly
|
||||||
contentType = "submodule"
|
contentType = "submodule"
|
||||||
} else if entry.IsLink() {
|
} else if entry.IsSymlink() {
|
||||||
contentType = "symlink"
|
contentType = "symlink"
|
||||||
blob, err := c.Repo.Commit.GetBlobByPath(c.Repo.TreePath)
|
blob, err := c.Repo.Commit.Blob(c.Repo.TreePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ServerError("GetBlobByPath", err)
|
c.ServerError("GetBlobByPath", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
b, err := blob.Data()
|
p, err := blob.Bytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ServerError("Data", err)
|
c.ServerError("Data", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
buf, err := ioutil.ReadAll(b)
|
contents.Target = string(p)
|
||||||
if err != nil {
|
|
||||||
c.ServerError("ReadAll", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
contents.Target = string(buf)
|
|
||||||
} else {
|
} else {
|
||||||
contentType = "file"
|
contentType = "file"
|
||||||
}
|
}
|
||||||
@@ -187,7 +172,7 @@ func GetContents(c *context.APIContext) {
|
|||||||
Size: entry.Size(),
|
Size: entry.Size(),
|
||||||
Name: entry.Name(),
|
Name: entry.Name(),
|
||||||
Path: c.Repo.TreePath,
|
Path: c.Repo.TreePath,
|
||||||
Sha: entry.ID.String(),
|
Sha: entry.ID().String(),
|
||||||
URL: selfURL,
|
URL: selfURL,
|
||||||
GitURL: gitURL,
|
GitURL: gitURL,
|
||||||
HTMLURL: htmlURL,
|
HTMLURL: htmlURL,
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
|
|
||||||
"gogs.io/gogs/internal/context"
|
"gogs.io/gogs/internal/context"
|
||||||
"gogs.io/gogs/internal/db"
|
"gogs.io/gogs/internal/db"
|
||||||
|
"gogs.io/gogs/internal/gitutil"
|
||||||
"gogs.io/gogs/internal/route/repo"
|
"gogs.io/gogs/internal/route/repo"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -23,9 +24,9 @@ func GetRawFile(c *context.APIContext) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
blob, err := c.Repo.Commit.GetBlobByPath(c.Repo.TreePath)
|
blob, err := c.Repo.Commit.Blob(c.Repo.TreePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.NotFoundOrServerError("GetBlobByPath", git.IsErrNotExist, err)
|
c.NotFoundOrServerError("get blob", gitutil.IsErrRevisionNotExist, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err = repo.ServeBlob(c.Context, blob); err != nil {
|
if err = repo.ServeBlob(c.Context, blob); err != nil {
|
||||||
@@ -35,9 +36,9 @@ func GetRawFile(c *context.APIContext) {
|
|||||||
|
|
||||||
func GetArchive(c *context.APIContext) {
|
func GetArchive(c *context.APIContext) {
|
||||||
repoPath := db.RepoPath(c.Params(":username"), c.Params(":reponame"))
|
repoPath := db.RepoPath(c.Params(":username"), c.Params(":reponame"))
|
||||||
gitRepo, err := git.OpenRepository(repoPath)
|
gitRepo, err := git.Open(repoPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ServerError("OpenRepository", err)
|
c.ServerError("open repository", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.Repo.GitRepo = gitRepo
|
c.Repo.GitRepo = gitRepo
|
||||||
@@ -46,16 +47,16 @@ func GetArchive(c *context.APIContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetEditorconfig(c *context.APIContext) {
|
func GetEditorconfig(c *context.APIContext) {
|
||||||
ec, err := c.Repo.GetEditorconfig()
|
ec, err := c.Repo.Editorconfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.NotFoundOrServerError("GetEditorconfig", git.IsErrNotExist, err)
|
c.NotFoundOrServerError("get .editorconfig", gitutil.IsErrRevisionNotExist, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fileName := c.Params("filename")
|
fileName := c.Params("filename")
|
||||||
def, err := ec.GetDefinitionForFilename(fileName)
|
def, err := ec.GetDefinitionForFilename(fileName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ServerError("GetDefinitionForFilename", err)
|
c.ServerError("get definition for filename", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if def == nil {
|
if def == nil {
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
// Copyright 2020 The Gogs Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package repo
|
package repo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -6,6 +10,7 @@ import (
|
|||||||
"github.com/gogs/git-module"
|
"github.com/gogs/git-module"
|
||||||
|
|
||||||
"gogs.io/gogs/internal/context"
|
"gogs.io/gogs/internal/context"
|
||||||
|
"gogs.io/gogs/internal/gitutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
type repoGitTree struct {
|
type repoGitTree struct {
|
||||||
@@ -24,14 +29,14 @@ type repoGitTreeEntry struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetRepoGitTree(c *context.APIContext) {
|
func GetRepoGitTree(c *context.APIContext) {
|
||||||
gitTree, err := c.Repo.GitRepo.GetTree(c.Params(":sha"))
|
gitTree, err := c.Repo.GitRepo.LsTree(c.Params(":sha"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.NotFoundOrServerError("GetRepoGitTree", git.IsErrNotExist, err)
|
c.NotFoundOrServerError("get tree", gitutil.IsErrRevisionNotExist, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
entries, err := gitTree.ListEntries()
|
entries, err := gitTree.Entries()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ServerError("GetRepoGitTree", err)
|
c.ServerError("list entries", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,7 +53,7 @@ func GetRepoGitTree(c *context.APIContext) {
|
|||||||
children := make([]*repoGitTreeEntry, 0, len(entries))
|
children := make([]*repoGitTreeEntry, 0, len(entries))
|
||||||
for _, entry := range entries {
|
for _, entry := range entries {
|
||||||
var mode string
|
var mode string
|
||||||
switch entry.Type {
|
switch entry.Type() {
|
||||||
case git.ObjectCommit:
|
case git.ObjectCommit:
|
||||||
mode = "160000"
|
mode = "160000"
|
||||||
case git.ObjectTree:
|
case git.ObjectTree:
|
||||||
@@ -63,10 +68,10 @@ func GetRepoGitTree(c *context.APIContext) {
|
|||||||
children = append(children, &repoGitTreeEntry{
|
children = append(children, &repoGitTreeEntry{
|
||||||
Path: entry.Name(),
|
Path: entry.Name(),
|
||||||
Mode: mode,
|
Mode: mode,
|
||||||
Type: string(entry.Type),
|
Type: string(entry.Type()),
|
||||||
Size: entry.Size(),
|
Size: entry.Size(),
|
||||||
Sha: entry.ID.String(),
|
Sha: entry.ID().String(),
|
||||||
URL: fmt.Sprintf(templateURL+"/%s", entry.ID.String()),
|
URL: fmt.Sprintf(templateURL+"/%s", entry.ID().String()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
c.JSONSuccess(&repoGitTree{
|
c.JSONSuccess(&repoGitTree{
|
||||||
|
|||||||
@@ -41,9 +41,9 @@ func checkRunMode() {
|
|||||||
if conf.IsProdMode() {
|
if conf.IsProdMode() {
|
||||||
macaron.Env = macaron.PROD
|
macaron.Env = macaron.PROD
|
||||||
macaron.ColorLog = false
|
macaron.ColorLog = false
|
||||||
git.Debug = false
|
git.SetOutput(nil)
|
||||||
} else {
|
} else {
|
||||||
git.Debug = true
|
git.SetOutput(os.Stdout)
|
||||||
}
|
}
|
||||||
log.Info("Run mode: %s", strings.Title(macaron.Env))
|
log.Info("Run mode: %s", strings.Title(macaron.Env))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,11 +119,11 @@ func DeleteBranchPost(c *context.Context) {
|
|||||||
c.Redirect(redirectTo)
|
c.Redirect(redirectTo)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if !c.Repo.GitRepo.IsBranchExist(branchName) {
|
if !c.Repo.GitRepo.HasBranch(branchName) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(commitID) > 0 {
|
if len(commitID) > 0 {
|
||||||
branchCommitID, err := c.Repo.GitRepo.GetBranchCommitID(branchName)
|
branchCommitID, err := c.Repo.GitRepo.BranchCommitID(branchName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Failed to get commit ID of branch %q: %v", branchName, err)
|
log.Error("Failed to get commit ID of branch %q: %v", branchName, err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
package repo
|
package repo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"container/list"
|
|
||||||
"path"
|
"path"
|
||||||
|
|
||||||
"github.com/gogs/git-module"
|
"github.com/gogs/git-module"
|
||||||
@@ -13,6 +12,7 @@ import (
|
|||||||
"gogs.io/gogs/internal/conf"
|
"gogs.io/gogs/internal/conf"
|
||||||
"gogs.io/gogs/internal/context"
|
"gogs.io/gogs/internal/context"
|
||||||
"gogs.io/gogs/internal/db"
|
"gogs.io/gogs/internal/db"
|
||||||
|
"gogs.io/gogs/internal/gitutil"
|
||||||
"gogs.io/gogs/internal/tool"
|
"gogs.io/gogs/internal/tool"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -33,13 +33,9 @@ func RefCommits(c *context.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func RenderIssueLinks(oldCommits *list.List, repoLink string) *list.List {
|
// TODO(unknwon)
|
||||||
newCommits := list.New()
|
func RenderIssueLinks(oldCommits []*git.Commit, repoLink string) []*git.Commit {
|
||||||
for e := oldCommits.Front(); e != nil; e = e.Next() {
|
return oldCommits
|
||||||
c := e.Value.(*git.Commit)
|
|
||||||
newCommits.PushBack(c)
|
|
||||||
}
|
|
||||||
return newCommits
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func renderCommits(c *context.Context, filename string) {
|
func renderCommits(c *context.Context, filename string) {
|
||||||
@@ -53,30 +49,23 @@ func renderCommits(c *context.Context, filename string) {
|
|||||||
}
|
}
|
||||||
pageSize := c.QueryInt("pageSize")
|
pageSize := c.QueryInt("pageSize")
|
||||||
if pageSize < 1 {
|
if pageSize < 1 {
|
||||||
pageSize = git.DefaultCommitsPageSize
|
pageSize = conf.UI.User.CommitsPagingNum
|
||||||
}
|
}
|
||||||
|
|
||||||
// Both 'git log branchName' and 'git log commitID' work.
|
commits, err := c.Repo.Commit.CommitsByPage(page, pageSize, git.CommitsByPageOptions{Path: filename})
|
||||||
var err error
|
|
||||||
var commits *list.List
|
|
||||||
if len(filename) == 0 {
|
|
||||||
commits, err = c.Repo.Commit.CommitsByRangeSize(page, pageSize)
|
|
||||||
} else {
|
|
||||||
commits, err = c.Repo.GitRepo.CommitsByFileAndRangeSize(c.Repo.BranchName, filename, page, pageSize)
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Handle(500, "CommitsByRangeSize/CommitsByFileAndRangeSize", err)
|
c.ServerError("paging commits", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
commits = RenderIssueLinks(commits, c.Repo.RepoLink)
|
commits = RenderIssueLinks(commits, c.Repo.RepoLink)
|
||||||
commits = db.ValidateCommitsWithEmails(commits)
|
c.Data["Commits"] = db.ValidateCommitsWithEmails(commits)
|
||||||
c.Data["Commits"] = commits
|
|
||||||
|
|
||||||
if page > 1 {
|
if page > 1 {
|
||||||
c.Data["HasPrevious"] = true
|
c.Data["HasPrevious"] = true
|
||||||
c.Data["PreviousPage"] = page - 1
|
c.Data["PreviousPage"] = page - 1
|
||||||
}
|
}
|
||||||
if commits.Len() == pageSize {
|
if len(commits) == pageSize {
|
||||||
c.Data["HasNext"] = true
|
c.Data["HasNext"] = true
|
||||||
c.Data["NextPage"] = page + 1
|
c.Data["NextPage"] = page + 1
|
||||||
}
|
}
|
||||||
@@ -102,12 +91,12 @@ func SearchCommits(c *context.Context) {
|
|||||||
|
|
||||||
commits, err := c.Repo.Commit.SearchCommits(keyword)
|
commits, err := c.Repo.Commit.SearchCommits(keyword)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Handle(500, "SearchCommits", err)
|
c.ServerError("SearchCommits", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
commits = RenderIssueLinks(commits, c.Repo.RepoLink)
|
commits = RenderIssueLinks(commits, c.Repo.RepoLink)
|
||||||
commits = db.ValidateCommitsWithEmails(commits)
|
c.Data["Commits"] = db.ValidateCommitsWithEmails(commits)
|
||||||
c.Data["Commits"] = commits
|
|
||||||
|
|
||||||
c.Data["Keyword"] = keyword
|
c.Data["Keyword"] = keyword
|
||||||
c.Data["Username"] = c.Repo.Owner.Name
|
c.Data["Username"] = c.Repo.Owner.Name
|
||||||
@@ -128,22 +117,23 @@ func Diff(c *context.Context) {
|
|||||||
repoName := c.Repo.Repository.Name
|
repoName := c.Repo.Repository.Name
|
||||||
commitID := c.Params(":sha")
|
commitID := c.Params(":sha")
|
||||||
|
|
||||||
commit, err := c.Repo.GitRepo.GetCommit(commitID)
|
commit, err := c.Repo.GitRepo.CatFileCommit(commitID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.NotFoundOrServerError("get commit by ID", git.IsErrNotExist, err)
|
// TODO: Move checker to gitutil package
|
||||||
|
c.NotFoundOrServerError("get commit by ID", gitutil.IsErrRevisionNotExist, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
diff, err := db.GetDiffCommit(db.RepoPath(userName, repoName),
|
diff, err := gitutil.RepoDiff(c.Repo.GitRepo,
|
||||||
commitID, conf.Git.MaxGitDiffLines,
|
commitID, conf.Git.MaxDiffFiles, conf.Git.MaxDiffLines, conf.Git.MaxDiffLineChars,
|
||||||
conf.Git.MaxGitDiffLineCharacters, conf.Git.MaxGitDiffFiles)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.NotFoundOrServerError("get diff commit", git.IsErrNotExist, err)
|
c.NotFoundOrServerError("get diff", gitutil.IsErrRevisionNotExist, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
parents := make([]string, commit.ParentCount())
|
parents := make([]string, commit.ParentsCount())
|
||||||
for i := 0; i < commit.ParentCount(); i++ {
|
for i := 0; i < commit.ParentsCount(); i++ {
|
||||||
sha, err := commit.ParentID(i)
|
sha, err := commit.ParentID(i)
|
||||||
parents[i] = sha.String()
|
parents[i] = sha.String()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -169,7 +159,7 @@ func Diff(c *context.Context) {
|
|||||||
c.Data["Parents"] = parents
|
c.Data["Parents"] = parents
|
||||||
c.Data["DiffNotAvailable"] = diff.NumFiles() == 0
|
c.Data["DiffNotAvailable"] = diff.NumFiles() == 0
|
||||||
c.Data["SourcePath"] = conf.Server.Subpath + "/" + path.Join(userName, repoName, "src", commitID)
|
c.Data["SourcePath"] = conf.Server.Subpath + "/" + path.Join(userName, repoName, "src", commitID)
|
||||||
if commit.ParentCount() > 0 {
|
if commit.ParentsCount() > 0 {
|
||||||
c.Data["BeforeSourcePath"] = conf.Server.Subpath + "/" + path.Join(userName, repoName, "src", parents[0])
|
c.Data["BeforeSourcePath"] = conf.Server.Subpath + "/" + path.Join(userName, repoName, "src", parents[0])
|
||||||
}
|
}
|
||||||
c.Data["RawPath"] = conf.Server.Subpath + "/" + path.Join(userName, repoName, "raw", commitID)
|
c.Data["RawPath"] = conf.Server.Subpath + "/" + path.Join(userName, repoName, "raw", commitID)
|
||||||
@@ -177,13 +167,12 @@ func Diff(c *context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func RawDiff(c *context.Context) {
|
func RawDiff(c *context.Context) {
|
||||||
if err := git.GetRawDiff(
|
if err := c.Repo.GitRepo.RawDiff(
|
||||||
db.RepoPath(c.Repo.Owner.Name, c.Repo.Repository.Name),
|
|
||||||
c.Params(":sha"),
|
c.Params(":sha"),
|
||||||
git.RawDiffType(c.Params(":ext")),
|
git.RawDiffFormat(c.Params(":ext")),
|
||||||
c.Resp,
|
c.Resp,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
c.NotFoundOrServerError("GetRawDiff", git.IsErrNotExist, err)
|
c.NotFoundOrServerError("get raw diff", gitutil.IsErrRevisionNotExist, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -195,31 +184,31 @@ func CompareDiff(c *context.Context) {
|
|||||||
beforeCommitID := c.Params(":before")
|
beforeCommitID := c.Params(":before")
|
||||||
afterCommitID := c.Params(":after")
|
afterCommitID := c.Params(":after")
|
||||||
|
|
||||||
commit, err := c.Repo.GitRepo.GetCommit(afterCommitID)
|
commit, err := c.Repo.GitRepo.CatFileCommit(afterCommitID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Handle(404, "GetCommit", err)
|
c.Handle(404, "GetCommit", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
diff, err := db.GetDiffRange(db.RepoPath(userName, repoName), beforeCommitID,
|
diff, err := gitutil.RepoDiff(c.Repo.GitRepo,
|
||||||
afterCommitID, conf.Git.MaxGitDiffLines,
|
afterCommitID, conf.Git.MaxDiffFiles, conf.Git.MaxDiffLines, conf.Git.MaxDiffLineChars,
|
||||||
conf.Git.MaxGitDiffLineCharacters, conf.Git.MaxGitDiffFiles)
|
git.DiffOptions{Base: beforeCommitID},
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Handle(404, "GetDiffRange", err)
|
c.ServerError("get diff", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
commits, err := commit.CommitsBeforeUntil(beforeCommitID)
|
commits, err := commit.CommitsAfter(beforeCommitID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Handle(500, "CommitsBeforeUntil", err)
|
c.ServerError("get commits after", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
commits = db.ValidateCommitsWithEmails(commits)
|
|
||||||
|
|
||||||
c.Data["IsSplitStyle"] = c.Query("style") == "split"
|
c.Data["IsSplitStyle"] = c.Query("style") == "split"
|
||||||
c.Data["CommitRepoLink"] = c.Repo.RepoLink
|
c.Data["CommitRepoLink"] = c.Repo.RepoLink
|
||||||
c.Data["Commits"] = commits
|
c.Data["Commits"] = db.ValidateCommitsWithEmails(commits)
|
||||||
c.Data["CommitsCount"] = commits.Len()
|
c.Data["CommitsCount"] = len(commits)
|
||||||
c.Data["BeforeCommitID"] = beforeCommitID
|
c.Data["BeforeCommitID"] = beforeCommitID
|
||||||
c.Data["AfterCommitID"] = afterCommitID
|
c.Data["AfterCommitID"] = afterCommitID
|
||||||
c.Data["Username"] = userName
|
c.Data["Username"] = userName
|
||||||
|
|||||||
@@ -6,32 +6,26 @@ package repo
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"path"
|
"path"
|
||||||
|
|
||||||
"github.com/gogs/git-module"
|
"github.com/gogs/git-module"
|
||||||
|
|
||||||
"gogs.io/gogs/internal/context"
|
|
||||||
"gogs.io/gogs/internal/conf"
|
"gogs.io/gogs/internal/conf"
|
||||||
|
"gogs.io/gogs/internal/context"
|
||||||
|
"gogs.io/gogs/internal/gitutil"
|
||||||
"gogs.io/gogs/internal/tool"
|
"gogs.io/gogs/internal/tool"
|
||||||
)
|
)
|
||||||
|
|
||||||
func serveData(c *context.Context, name string, r io.Reader) error {
|
func serveData(c *context.Context, name string, data []byte) error {
|
||||||
buf := make([]byte, 1024)
|
commit, err := c.Repo.Commit.CommitByPath(git.CommitByRevisionOptions{Path: c.Repo.TreePath})
|
||||||
n, _ := r.Read(buf)
|
|
||||||
if n >= 0 {
|
|
||||||
buf = buf[:n]
|
|
||||||
}
|
|
||||||
|
|
||||||
commit, err := c.Repo.Commit.GetCommitByPath(c.Repo.TreePath)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("GetCommitByPath: %v", err)
|
return fmt.Errorf("get commit by path %q: %v", c.Repo.TreePath, err)
|
||||||
}
|
}
|
||||||
c.Resp.Header().Set("Last-Modified", commit.Committer.When.Format(http.TimeFormat))
|
c.Resp.Header().Set("Last-Modified", commit.Committer.When.Format(http.TimeFormat))
|
||||||
|
|
||||||
if !tool.IsTextFile(buf) {
|
if !tool.IsTextFile(data) {
|
||||||
if !tool.IsImageFile(buf) {
|
if !tool.IsImageFile(data) {
|
||||||
c.Resp.Header().Set("Content-Disposition", "attachment; filename=\""+name+"\"")
|
c.Resp.Header().Set("Content-Disposition", "attachment; filename=\""+name+"\"")
|
||||||
c.Resp.Header().Set("Content-Transfer-Encoding", "binary")
|
c.Resp.Header().Set("Content-Transfer-Encoding", "binary")
|
||||||
}
|
}
|
||||||
@@ -39,33 +33,30 @@ func serveData(c *context.Context, name string, r io.Reader) error {
|
|||||||
c.Resp.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
c.Resp.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := c.Resp.Write(buf); err != nil {
|
if _, err := c.Resp.Write(data); err != nil {
|
||||||
return fmt.Errorf("write buffer to response: %v", err)
|
return fmt.Errorf("write buffer to response: %v", err)
|
||||||
}
|
}
|
||||||
_, err = io.Copy(c.Resp, r)
|
return nil
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ServeBlob(c *context.Context, blob *git.Blob) error {
|
func ServeBlob(c *context.Context, blob *git.Blob) error {
|
||||||
dataRc, err := blob.Data()
|
p, err := blob.Bytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return serveData(c, path.Base(c.Repo.TreePath), dataRc)
|
return serveData(c, path.Base(c.Repo.TreePath), p)
|
||||||
}
|
}
|
||||||
|
|
||||||
func SingleDownload(c *context.Context) {
|
func SingleDownload(c *context.Context) {
|
||||||
blob, err := c.Repo.Commit.GetBlobByPath(c.Repo.TreePath)
|
blob, err := c.Repo.Commit.Blob(c.Repo.TreePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if git.IsErrNotExist(err) {
|
c.NotFoundOrServerError("get blob", gitutil.IsErrRevisionNotExist, err)
|
||||||
c.Handle(404, "GetBlobByPath", nil)
|
|
||||||
} else {
|
|
||||||
c.Handle(500, "GetBlobByPath", err)
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = ServeBlob(c, blob); err != nil {
|
if err = ServeBlob(c, blob); err != nil {
|
||||||
c.Handle(500, "ServeBlob", err)
|
c.ServerError("serve blob", err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,19 +6,18 @@ package repo
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
log "unknwon.dev/clog/v2"
|
log "unknwon.dev/clog/v2"
|
||||||
|
|
||||||
"github.com/gogs/git-module"
|
|
||||||
"gogs.io/gogs/internal/conf"
|
"gogs.io/gogs/internal/conf"
|
||||||
"gogs.io/gogs/internal/context"
|
"gogs.io/gogs/internal/context"
|
||||||
"gogs.io/gogs/internal/db"
|
"gogs.io/gogs/internal/db"
|
||||||
"gogs.io/gogs/internal/db/errors"
|
"gogs.io/gogs/internal/db/errors"
|
||||||
"gogs.io/gogs/internal/form"
|
"gogs.io/gogs/internal/form"
|
||||||
|
"gogs.io/gogs/internal/gitutil"
|
||||||
"gogs.io/gogs/internal/pathutil"
|
"gogs.io/gogs/internal/pathutil"
|
||||||
"gogs.io/gogs/internal/template"
|
"gogs.io/gogs/internal/template"
|
||||||
"gogs.io/gogs/internal/tool"
|
"gogs.io/gogs/internal/tool"
|
||||||
@@ -55,20 +54,20 @@ func editFile(c *context.Context, isNewFile bool) {
|
|||||||
treeNames, treePaths := getParentTreeFields(c.Repo.TreePath)
|
treeNames, treePaths := getParentTreeFields(c.Repo.TreePath)
|
||||||
|
|
||||||
if !isNewFile {
|
if !isNewFile {
|
||||||
entry, err := c.Repo.Commit.GetTreeEntryByPath(c.Repo.TreePath)
|
entry, err := c.Repo.Commit.TreeEntry(c.Repo.TreePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.NotFoundOrServerError("GetTreeEntryByPath", git.IsErrNotExist, err)
|
c.NotFoundOrServerError("get tree entry", gitutil.IsErrRevisionNotExist, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// No way to edit a directory online.
|
// No way to edit a directory online.
|
||||||
if entry.IsDir() {
|
if entry.IsTree() {
|
||||||
c.NotFound()
|
c.NotFound()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
blob := entry.Blob()
|
blob := entry.Blob()
|
||||||
dataRc, err := blob.Data()
|
p, err := blob.Bytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ServerError("blob.Data", err)
|
c.ServerError("blob.Data", err)
|
||||||
return
|
return
|
||||||
@@ -77,23 +76,17 @@ func editFile(c *context.Context, isNewFile bool) {
|
|||||||
c.Data["FileSize"] = blob.Size()
|
c.Data["FileSize"] = blob.Size()
|
||||||
c.Data["FileName"] = blob.Name()
|
c.Data["FileName"] = blob.Name()
|
||||||
|
|
||||||
buf := make([]byte, 1024)
|
|
||||||
n, _ := dataRc.Read(buf)
|
|
||||||
buf = buf[:n]
|
|
||||||
|
|
||||||
// Only text file are editable online.
|
// Only text file are editable online.
|
||||||
if !tool.IsTextFile(buf) {
|
if !tool.IsTextFile(p) {
|
||||||
c.NotFound()
|
c.NotFound()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
d, _ := ioutil.ReadAll(dataRc)
|
if err, content := template.ToUTF8WithErr(p); err != nil {
|
||||||
buf = append(buf, d...)
|
|
||||||
if err, content := template.ToUTF8WithErr(buf); err != nil {
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Failed to convert encoding to UTF-8: %v", err)
|
log.Error("Failed to convert encoding to UTF-8: %v", err)
|
||||||
}
|
}
|
||||||
c.Data["FileContent"] = string(buf)
|
c.Data["FileContent"] = string(p)
|
||||||
} else {
|
} else {
|
||||||
c.Data["FileContent"] = content
|
c.Data["FileContent"] = content
|
||||||
}
|
}
|
||||||
@@ -182,9 +175,9 @@ func editFilePost(c *context.Context, f form.EditRepoFile, isNewFile bool) {
|
|||||||
var newTreePath string
|
var newTreePath string
|
||||||
for index, part := range treeNames {
|
for index, part := range treeNames {
|
||||||
newTreePath = path.Join(newTreePath, part)
|
newTreePath = path.Join(newTreePath, part)
|
||||||
entry, err := c.Repo.Commit.GetTreeEntryByPath(newTreePath)
|
entry, err := c.Repo.Commit.TreeEntry(newTreePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if git.IsErrNotExist(err) {
|
if gitutil.IsErrRevisionNotExist(err) {
|
||||||
// Means there is no item with that name, so we're good
|
// Means there is no item with that name, so we're good
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -193,17 +186,17 @@ func editFilePost(c *context.Context, f form.EditRepoFile, isNewFile bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if index != len(treeNames)-1 {
|
if index != len(treeNames)-1 {
|
||||||
if !entry.IsDir() {
|
if !entry.IsTree() {
|
||||||
c.FormErr("TreePath")
|
c.FormErr("TreePath")
|
||||||
c.RenderWithErr(c.Tr("repo.editor.directory_is_a_file", part), EDIT_FILE, &f)
|
c.RenderWithErr(c.Tr("repo.editor.directory_is_a_file", part), EDIT_FILE, &f)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if entry.IsLink() {
|
if entry.IsSymlink() {
|
||||||
c.FormErr("TreePath")
|
c.FormErr("TreePath")
|
||||||
c.RenderWithErr(c.Tr("repo.editor.file_is_a_symlink", part), EDIT_FILE, &f)
|
c.RenderWithErr(c.Tr("repo.editor.file_is_a_symlink", part), EDIT_FILE, &f)
|
||||||
return
|
return
|
||||||
} else if entry.IsDir() {
|
} else if entry.IsTree() {
|
||||||
c.FormErr("TreePath")
|
c.FormErr("TreePath")
|
||||||
c.RenderWithErr(c.Tr("repo.editor.filename_is_a_directory", part), EDIT_FILE, &f)
|
c.RenderWithErr(c.Tr("repo.editor.filename_is_a_directory", part), EDIT_FILE, &f)
|
||||||
return
|
return
|
||||||
@@ -212,9 +205,9 @@ func editFilePost(c *context.Context, f form.EditRepoFile, isNewFile bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !isNewFile {
|
if !isNewFile {
|
||||||
_, err := c.Repo.Commit.GetTreeEntryByPath(oldTreePath)
|
_, err := c.Repo.Commit.TreeEntry(oldTreePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if git.IsErrNotExist(err) {
|
if gitutil.IsErrRevisionNotExist(err) {
|
||||||
c.FormErr("TreePath")
|
c.FormErr("TreePath")
|
||||||
c.RenderWithErr(c.Tr("repo.editor.file_editing_no_longer_exists", oldTreePath), EDIT_FILE, &f)
|
c.RenderWithErr(c.Tr("repo.editor.file_editing_no_longer_exists", oldTreePath), EDIT_FILE, &f)
|
||||||
} else {
|
} else {
|
||||||
@@ -223,7 +216,7 @@ func editFilePost(c *context.Context, f form.EditRepoFile, isNewFile bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if lastCommit != c.Repo.CommitID {
|
if lastCommit != c.Repo.CommitID {
|
||||||
files, err := c.Repo.Commit.GetFilesChangedSinceCommit(lastCommit)
|
files, err := c.Repo.Commit.FilesChangedAfter(lastCommit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ServerError("GetFilesChangedSinceCommit", err)
|
c.ServerError("GetFilesChangedSinceCommit", err)
|
||||||
return
|
return
|
||||||
@@ -240,9 +233,9 @@ func editFilePost(c *context.Context, f form.EditRepoFile, isNewFile bool) {
|
|||||||
|
|
||||||
if oldTreePath != f.TreePath {
|
if oldTreePath != f.TreePath {
|
||||||
// We have a new filename (rename or completely new file) so we need to make sure it doesn't already exist, can't clobber.
|
// We have a new filename (rename or completely new file) so we need to make sure it doesn't already exist, can't clobber.
|
||||||
entry, err := c.Repo.Commit.GetTreeEntryByPath(f.TreePath)
|
entry, err := c.Repo.Commit.TreeEntry(f.TreePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !git.IsErrNotExist(err) {
|
if !gitutil.IsErrRevisionNotExist(err) {
|
||||||
c.ServerError("GetTreeEntryByPath", err)
|
c.ServerError("GetTreeEntryByPath", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -302,11 +295,11 @@ func NewFilePost(c *context.Context, f form.EditRepoFile) {
|
|||||||
func DiffPreviewPost(c *context.Context, f form.EditPreviewDiff) {
|
func DiffPreviewPost(c *context.Context, f form.EditPreviewDiff) {
|
||||||
treePath := c.Repo.TreePath
|
treePath := c.Repo.TreePath
|
||||||
|
|
||||||
entry, err := c.Repo.Commit.GetTreeEntryByPath(treePath)
|
entry, err := c.Repo.Commit.TreeEntry(treePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Error(500, "GetTreeEntryByPath: "+err.Error())
|
c.Error(500, "GetTreeEntryByPath: "+err.Error())
|
||||||
return
|
return
|
||||||
} else if entry.IsDir() {
|
} else if entry.IsTree() {
|
||||||
c.Error(422)
|
c.Error(422)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -468,9 +461,9 @@ func UploadFilePost(c *context.Context, f form.UploadRepoFile) {
|
|||||||
var newTreePath string
|
var newTreePath string
|
||||||
for _, part := range treeNames {
|
for _, part := range treeNames {
|
||||||
newTreePath = path.Join(newTreePath, part)
|
newTreePath = path.Join(newTreePath, part)
|
||||||
entry, err := c.Repo.Commit.GetTreeEntryByPath(newTreePath)
|
entry, err := c.Repo.Commit.TreeEntry(newTreePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if git.IsErrNotExist(err) {
|
if gitutil.IsErrRevisionNotExist(err) {
|
||||||
// Means there is no item with that name, so we're good
|
// Means there is no item with that name, so we're good
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -480,7 +473,7 @@ func UploadFilePost(c *context.Context, f form.UploadRepoFile) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// User can only upload files to a directory.
|
// User can only upload files to a directory.
|
||||||
if !entry.IsDir() {
|
if !entry.IsTree() {
|
||||||
c.FormErr("TreePath")
|
c.FormErr("TreePath")
|
||||||
c.RenderWithErr(c.Tr("repo.editor.directory_is_a_file", part), UPLOAD_FILE, &f)
|
c.RenderWithErr(c.Tr("repo.editor.directory_is_a_file", part), UPLOAD_FILE, &f)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ package repo
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -303,30 +301,23 @@ func RetrieveRepoMetas(c *context.Context, repo *db.Repository) []*db.Label {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getFileContentFromDefaultBranch(c *context.Context, filename string) (string, bool) {
|
func getFileContentFromDefaultBranch(c *context.Context, filename string) (string, bool) {
|
||||||
var r io.Reader
|
|
||||||
var bytes []byte
|
|
||||||
|
|
||||||
if c.Repo.Commit == nil {
|
if c.Repo.Commit == nil {
|
||||||
var err error
|
var err error
|
||||||
c.Repo.Commit, err = c.Repo.GitRepo.GetBranchCommit(c.Repo.Repository.DefaultBranch)
|
c.Repo.Commit, err = c.Repo.GitRepo.BranchCommit(c.Repo.Repository.DefaultBranch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
entry, err := c.Repo.Commit.GetTreeEntryByPath(filename)
|
entry, err := c.Repo.Commit.TreeEntry(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
r, err = entry.Blob().Data()
|
p, err := entry.Blob().Bytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
bytes, err = ioutil.ReadAll(r)
|
return string(p), true
|
||||||
if err != nil {
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
return string(bytes), true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func setTemplateIfExists(c *context.Context, ctxDataKey string, possibleFiles []string) {
|
func setTemplateIfExists(c *context.Context, ctxDataKey string, possibleFiles []string) {
|
||||||
@@ -656,7 +647,7 @@ func viewIssue(c *context.Context, isPullList bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
c.Data["IsPullBranchDeletable"] = pull.BaseRepoID == pull.HeadRepoID &&
|
c.Data["IsPullBranchDeletable"] = pull.BaseRepoID == pull.HeadRepoID &&
|
||||||
c.Repo.IsWriter() && c.Repo.GitRepo.IsBranchExist(pull.HeadBranch) &&
|
c.Repo.IsWriter() && c.Repo.GitRepo.HasBranch(pull.HeadBranch) &&
|
||||||
!branchProtected
|
!branchProtected
|
||||||
|
|
||||||
c.Data["DeleteBranchLink"] = c.Repo.MakeURL(url.URL{
|
c.Data["DeleteBranchLink"] = c.Repo.MakeURL(url.URL{
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
package repo
|
package repo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"container/list"
|
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -19,6 +18,7 @@ import (
|
|||||||
"gogs.io/gogs/internal/db"
|
"gogs.io/gogs/internal/db"
|
||||||
"gogs.io/gogs/internal/db/errors"
|
"gogs.io/gogs/internal/db/errors"
|
||||||
"gogs.io/gogs/internal/form"
|
"gogs.io/gogs/internal/form"
|
||||||
|
"gogs.io/gogs/internal/gitutil"
|
||||||
"gogs.io/gogs/internal/tool"
|
"gogs.io/gogs/internal/tool"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -183,19 +183,21 @@ func PrepareMergedViewPullInfo(c *context.Context, issue *db.Issue) {
|
|||||||
c.Data["BaseTarget"] = c.Repo.Owner.Name + "/" + pull.BaseBranch
|
c.Data["BaseTarget"] = c.Repo.Owner.Name + "/" + pull.BaseBranch
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
c.Data["NumCommits"], err = c.Repo.GitRepo.CommitsCountBetween(pull.MergeBase, pull.MergedCommitID)
|
c.Data["NumCommits"], err = c.Repo.GitRepo.RevListCount([]string{pull.MergeBase + "..." + pull.MergedCommitID})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ServerError("Repo.GitRepo.CommitsCountBetween", err)
|
c.ServerError("Repo.GitRepo.CommitsCountBetween", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.Data["NumFiles"], err = c.Repo.GitRepo.FilesCountBetween(pull.MergeBase, pull.MergedCommitID)
|
|
||||||
|
names, err := c.Repo.GitRepo.DiffNameOnly(pull.MergeBase, pull.MergedCommitID, git.DiffNameOnlyOptions{NeedsMergeBase: true})
|
||||||
|
c.Data["NumFiles"] = len(names)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ServerError("Repo.GitRepo.FilesCountBetween", err)
|
c.ServerError("Repo.GitRepo.FilesCountBetween", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func PrepareViewPullInfo(c *context.Context, issue *db.Issue) *git.PullRequestInfo {
|
func PrepareViewPullInfo(c *context.Context, issue *db.Issue) *gitutil.PullRequestMeta {
|
||||||
repo := c.Repo.Repository
|
repo := c.Repo.Repository
|
||||||
pull := issue.PullRequest
|
pull := issue.PullRequest
|
||||||
|
|
||||||
@@ -208,14 +210,14 @@ func PrepareViewPullInfo(c *context.Context, issue *db.Issue) *git.PullRequestIn
|
|||||||
)
|
)
|
||||||
|
|
||||||
if pull.HeadRepo != nil {
|
if pull.HeadRepo != nil {
|
||||||
headGitRepo, err = git.OpenRepository(pull.HeadRepo.RepoPath())
|
headGitRepo, err = git.Open(pull.HeadRepo.RepoPath())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ServerError("OpenRepository", err)
|
c.ServerError("open repository", err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if pull.HeadRepo == nil || !headGitRepo.IsBranchExist(pull.HeadBranch) {
|
if pull.HeadRepo == nil || !headGitRepo.HasBranch(pull.HeadBranch) {
|
||||||
c.Data["IsPullReuqestBroken"] = true
|
c.Data["IsPullReuqestBroken"] = true
|
||||||
c.Data["HeadTarget"] = "deleted"
|
c.Data["HeadTarget"] = "deleted"
|
||||||
c.Data["NumCommits"] = 0
|
c.Data["NumCommits"] = 0
|
||||||
@@ -223,8 +225,8 @@ func PrepareViewPullInfo(c *context.Context, issue *db.Issue) *git.PullRequestIn
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
prInfo, err := headGitRepo.GetPullRequestInfo(db.RepoPath(repo.Owner.Name, repo.Name),
|
baseRepoPath := db.RepoPath(repo.Owner.Name, repo.Name)
|
||||||
pull.BaseBranch, pull.HeadBranch)
|
prMeta, err := gitutil.Module.PullRequestMeta(headGitRepo.Path(), baseRepoPath, pull.HeadBranch, pull.BaseBranch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if strings.Contains(err.Error(), "fatal: Not a valid object name") {
|
if strings.Contains(err.Error(), "fatal: Not a valid object name") {
|
||||||
c.Data["IsPullReuqestBroken"] = true
|
c.Data["IsPullReuqestBroken"] = true
|
||||||
@@ -237,9 +239,9 @@ func PrepareViewPullInfo(c *context.Context, issue *db.Issue) *git.PullRequestIn
|
|||||||
c.ServerError("GetPullRequestInfo", err)
|
c.ServerError("GetPullRequestInfo", err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
c.Data["NumCommits"] = prInfo.Commits.Len()
|
c.Data["NumCommits"] = len(prMeta.Commits)
|
||||||
c.Data["NumFiles"] = prInfo.NumFiles
|
c.Data["NumFiles"] = prMeta.NumFiles
|
||||||
return prInfo
|
return prMeta
|
||||||
}
|
}
|
||||||
|
|
||||||
func ViewPullCommits(c *context.Context) {
|
func ViewPullCommits(c *context.Context) {
|
||||||
@@ -257,25 +259,25 @@ func ViewPullCommits(c *context.Context) {
|
|||||||
c.Data["Reponame"] = pull.HeadRepo.Name
|
c.Data["Reponame"] = pull.HeadRepo.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
var commits *list.List
|
var commits []*git.Commit
|
||||||
if pull.HasMerged {
|
if pull.HasMerged {
|
||||||
PrepareMergedViewPullInfo(c, issue)
|
PrepareMergedViewPullInfo(c, issue)
|
||||||
if c.Written() {
|
if c.Written() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
startCommit, err := c.Repo.GitRepo.GetCommit(pull.MergeBase)
|
startCommit, err := c.Repo.GitRepo.CatFileCommit(pull.MergeBase)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ServerError("Repo.GitRepo.GetCommit", err)
|
c.ServerError("get commit of merge base", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
endCommit, err := c.Repo.GitRepo.GetCommit(pull.MergedCommitID)
|
endCommit, err := c.Repo.GitRepo.CatFileCommit(pull.MergedCommitID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ServerError("Repo.GitRepo.GetCommit", err)
|
c.ServerError("get merged commit", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
commits, err = c.Repo.GitRepo.CommitsBetween(endCommit, startCommit)
|
commits, err = c.Repo.GitRepo.RevList([]string{startCommit.ID.String() + "..." + endCommit.ID.String()})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ServerError("Repo.GitRepo.CommitsBetween", err)
|
c.ServerError("list commits", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -290,9 +292,8 @@ func ViewPullCommits(c *context.Context) {
|
|||||||
commits = prInfo.Commits
|
commits = prInfo.Commits
|
||||||
}
|
}
|
||||||
|
|
||||||
commits = db.ValidateCommitsWithEmails(commits)
|
c.Data["Commits"] = db.ValidateCommitsWithEmails(commits)
|
||||||
c.Data["Commits"] = commits
|
c.Data["CommitsCount"] = len(commits)
|
||||||
c.Data["CommitsCount"] = commits.Len()
|
|
||||||
|
|
||||||
c.Success(PULL_COMMITS)
|
c.Success(PULL_COMMITS)
|
||||||
}
|
}
|
||||||
@@ -308,7 +309,7 @@ func ViewPullFiles(c *context.Context) {
|
|||||||
pull := issue.PullRequest
|
pull := issue.PullRequest
|
||||||
|
|
||||||
var (
|
var (
|
||||||
diffRepoPath string
|
diffGitRepo *git.Repository
|
||||||
startCommitID string
|
startCommitID string
|
||||||
endCommitID string
|
endCommitID string
|
||||||
gitRepo *git.Repository
|
gitRepo *git.Repository
|
||||||
@@ -320,7 +321,7 @@ func ViewPullFiles(c *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
diffRepoPath = c.Repo.GitRepo.Path
|
diffGitRepo = c.Repo.GitRepo
|
||||||
startCommitID = pull.MergeBase
|
startCommitID = pull.MergeBase
|
||||||
endCommitID = pull.MergedCommitID
|
endCommitID = pull.MergedCommitID
|
||||||
gitRepo = c.Repo.GitRepo
|
gitRepo = c.Repo.GitRepo
|
||||||
@@ -335,37 +336,38 @@ func ViewPullFiles(c *context.Context) {
|
|||||||
|
|
||||||
headRepoPath := db.RepoPath(pull.HeadUserName, pull.HeadRepo.Name)
|
headRepoPath := db.RepoPath(pull.HeadUserName, pull.HeadRepo.Name)
|
||||||
|
|
||||||
headGitRepo, err := git.OpenRepository(headRepoPath)
|
headGitRepo, err := git.Open(headRepoPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ServerError("OpenRepository", err)
|
c.ServerError("open repository", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
headCommitID, err := headGitRepo.GetBranchCommitID(pull.HeadBranch)
|
headCommitID, err := headGitRepo.BranchCommitID(pull.HeadBranch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ServerError("GetBranchCommitID", err)
|
c.ServerError("get head branch commit ID", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
diffRepoPath = headRepoPath
|
diffGitRepo = headGitRepo
|
||||||
startCommitID = prInfo.MergeBase
|
startCommitID = prInfo.MergeBase
|
||||||
endCommitID = headCommitID
|
endCommitID = headCommitID
|
||||||
gitRepo = headGitRepo
|
gitRepo = headGitRepo
|
||||||
}
|
}
|
||||||
|
|
||||||
diff, err := db.GetDiffRange(diffRepoPath,
|
diff, err := gitutil.RepoDiff(diffGitRepo,
|
||||||
startCommitID, endCommitID, conf.Git.MaxGitDiffLines,
|
endCommitID, conf.Git.MaxDiffFiles, conf.Git.MaxDiffLines, conf.Git.MaxDiffLineChars,
|
||||||
conf.Git.MaxGitDiffLineCharacters, conf.Git.MaxGitDiffFiles)
|
git.DiffOptions{Base: startCommitID},
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ServerError("GetDiffRange", err)
|
c.ServerError("get diff", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.Data["Diff"] = diff
|
c.Data["Diff"] = diff
|
||||||
c.Data["DiffNotAvailable"] = diff.NumFiles() == 0
|
c.Data["DiffNotAvailable"] = diff.NumFiles() == 0
|
||||||
|
|
||||||
commit, err := gitRepo.GetCommit(endCommitID)
|
commit, err := gitRepo.CatFileCommit(endCommitID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ServerError("GetCommit", err)
|
c.ServerError("get commit", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -424,7 +426,7 @@ func MergePullRequest(c *context.Context) {
|
|||||||
c.Redirect(c.Repo.RepoLink + "/pulls/" + com.ToStr(pr.Index))
|
c.Redirect(c.Repo.RepoLink + "/pulls/" + com.ToStr(pr.Index))
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseCompareInfo(c *context.Context) (*db.User, *db.Repository, *git.Repository, *git.PullRequestInfo, string, string) {
|
func ParseCompareInfo(c *context.Context) (*db.User, *db.Repository, *git.Repository, *gitutil.PullRequestMeta, string, string) {
|
||||||
baseRepo := c.Repo.Repository
|
baseRepo := c.Repo.Repository
|
||||||
|
|
||||||
// Get compared branches information
|
// Get compared branches information
|
||||||
@@ -473,7 +475,7 @@ func ParseCompareInfo(c *context.Context) (*db.User, *db.Repository, *git.Reposi
|
|||||||
c.Repo.PullRequest.SameRepo = isSameRepo
|
c.Repo.PullRequest.SameRepo = isSameRepo
|
||||||
|
|
||||||
// Check if base branch is valid.
|
// Check if base branch is valid.
|
||||||
if !c.Repo.GitRepo.IsBranchExist(baseBranch) {
|
if !c.Repo.GitRepo.HasBranch(baseBranch) {
|
||||||
c.NotFound()
|
c.NotFound()
|
||||||
return nil, nil, nil, nil, "", ""
|
return nil, nil, nil, nil, "", ""
|
||||||
}
|
}
|
||||||
@@ -497,9 +499,9 @@ func ParseCompareInfo(c *context.Context) (*db.User, *db.Repository, *git.Reposi
|
|||||||
return nil, nil, nil, nil, "", ""
|
return nil, nil, nil, nil, "", ""
|
||||||
}
|
}
|
||||||
|
|
||||||
headGitRepo, err = git.OpenRepository(db.RepoPath(headUser.Name, headRepo.Name))
|
headGitRepo, err = git.Open(db.RepoPath(headUser.Name, headRepo.Name))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ServerError("OpenRepository", err)
|
c.ServerError("open repository", err)
|
||||||
return nil, nil, nil, nil, "", ""
|
return nil, nil, nil, nil, "", ""
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -514,31 +516,32 @@ func ParseCompareInfo(c *context.Context) (*db.User, *db.Repository, *git.Reposi
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if head branch is valid.
|
// Check if head branch is valid.
|
||||||
if !headGitRepo.IsBranchExist(headBranch) {
|
if !headGitRepo.HasBranch(headBranch) {
|
||||||
c.NotFound()
|
c.NotFound()
|
||||||
return nil, nil, nil, nil, "", ""
|
return nil, nil, nil, nil, "", ""
|
||||||
}
|
}
|
||||||
|
|
||||||
headBranches, err := headGitRepo.GetBranches()
|
headBranches, err := headGitRepo.Branches()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ServerError("GetBranches", err)
|
c.ServerError("get branches", err)
|
||||||
return nil, nil, nil, nil, "", ""
|
return nil, nil, nil, nil, "", ""
|
||||||
}
|
}
|
||||||
c.Data["HeadBranches"] = headBranches
|
c.Data["HeadBranches"] = headBranches
|
||||||
|
|
||||||
prInfo, err := headGitRepo.GetPullRequestInfo(db.RepoPath(baseRepo.Owner.Name, baseRepo.Name), baseBranch, headBranch)
|
baseRepoPath := db.RepoPath(baseRepo.Owner.Name, baseRepo.Name)
|
||||||
|
meta, err := gitutil.Module.PullRequestMeta(headGitRepo.Path(), baseRepoPath, headBranch, baseBranch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if git.IsErrNoMergeBase(err) {
|
if gitutil.IsErrNoMergeBase(err) {
|
||||||
c.Data["IsNoMergeBase"] = true
|
c.Data["IsNoMergeBase"] = true
|
||||||
c.Success(COMPARE_PULL)
|
c.Success(COMPARE_PULL)
|
||||||
} else {
|
} else {
|
||||||
c.ServerError("GetPullRequestInfo", err)
|
c.ServerError("get pull request meta", err)
|
||||||
}
|
}
|
||||||
return nil, nil, nil, nil, "", ""
|
return nil, nil, nil, nil, "", ""
|
||||||
}
|
}
|
||||||
c.Data["BeforeCommitID"] = prInfo.MergeBase
|
c.Data["BeforeCommitID"] = meta.MergeBase
|
||||||
|
|
||||||
return headUser, headRepo, headGitRepo, prInfo, baseBranch, headBranch
|
return headUser, headRepo, headGitRepo, meta, baseBranch, headBranch
|
||||||
}
|
}
|
||||||
|
|
||||||
func PrepareCompareDiff(
|
func PrepareCompareDiff(
|
||||||
@@ -546,8 +549,9 @@ func PrepareCompareDiff(
|
|||||||
headUser *db.User,
|
headUser *db.User,
|
||||||
headRepo *db.Repository,
|
headRepo *db.Repository,
|
||||||
headGitRepo *git.Repository,
|
headGitRepo *git.Repository,
|
||||||
prInfo *git.PullRequestInfo,
|
meta *gitutil.PullRequestMeta,
|
||||||
baseBranch, headBranch string) bool {
|
headBranch string,
|
||||||
|
) bool {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
repo = c.Repo.Repository
|
repo = c.Repo.Repository
|
||||||
@@ -557,44 +561,44 @@ func PrepareCompareDiff(
|
|||||||
// Get diff information.
|
// Get diff information.
|
||||||
c.Data["CommitRepoLink"] = headRepo.Link()
|
c.Data["CommitRepoLink"] = headRepo.Link()
|
||||||
|
|
||||||
headCommitID, err := headGitRepo.GetBranchCommitID(headBranch)
|
headCommitID, err := headGitRepo.BranchCommitID(headBranch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ServerError("GetBranchCommitID", err)
|
c.ServerError("get head branch commit ID", err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
c.Data["AfterCommitID"] = headCommitID
|
c.Data["AfterCommitID"] = headCommitID
|
||||||
|
|
||||||
if headCommitID == prInfo.MergeBase {
|
if headCommitID == meta.MergeBase {
|
||||||
c.Data["IsNothingToCompare"] = true
|
c.Data["IsNothingToCompare"] = true
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
diff, err := db.GetDiffRange(db.RepoPath(headUser.Name, headRepo.Name),
|
diff, err := gitutil.RepoDiff(headGitRepo,
|
||||||
prInfo.MergeBase, headCommitID, conf.Git.MaxGitDiffLines,
|
headCommitID, conf.Git.MaxDiffFiles, conf.Git.MaxDiffLines, conf.Git.MaxDiffLineChars,
|
||||||
conf.Git.MaxGitDiffLineCharacters, conf.Git.MaxGitDiffFiles)
|
git.DiffOptions{Base: meta.MergeBase},
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ServerError("GetDiffRange", err)
|
c.ServerError("get repository diff", err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
c.Data["Diff"] = diff
|
c.Data["Diff"] = diff
|
||||||
c.Data["DiffNotAvailable"] = diff.NumFiles() == 0
|
c.Data["DiffNotAvailable"] = diff.NumFiles() == 0
|
||||||
|
|
||||||
headCommit, err := headGitRepo.GetCommit(headCommitID)
|
headCommit, err := headGitRepo.CatFileCommit(headCommitID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ServerError("GetCommit", err)
|
c.ServerError("get head commit", err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
prInfo.Commits = db.ValidateCommitsWithEmails(prInfo.Commits)
|
c.Data["Commits"] = db.ValidateCommitsWithEmails(meta.Commits)
|
||||||
c.Data["Commits"] = prInfo.Commits
|
c.Data["CommitCount"] = len(meta.Commits)
|
||||||
c.Data["CommitCount"] = prInfo.Commits.Len()
|
|
||||||
c.Data["Username"] = headUser.Name
|
c.Data["Username"] = headUser.Name
|
||||||
c.Data["Reponame"] = headRepo.Name
|
c.Data["Reponame"] = headRepo.Name
|
||||||
c.Data["IsImageFile"] = headCommit.IsImageFile
|
c.Data["IsImageFile"] = headCommit.IsImageFile
|
||||||
|
|
||||||
headTarget := path.Join(headUser.Name, repo.Name)
|
headTarget := path.Join(headUser.Name, repo.Name)
|
||||||
c.Data["SourcePath"] = conf.Server.Subpath + "/" + path.Join(headTarget, "src", headCommitID)
|
c.Data["SourcePath"] = conf.Server.Subpath + "/" + path.Join(headTarget, "src", headCommitID)
|
||||||
c.Data["BeforeSourcePath"] = conf.Server.Subpath + "/" + path.Join(headTarget, "src", prInfo.MergeBase)
|
c.Data["BeforeSourcePath"] = conf.Server.Subpath + "/" + path.Join(headTarget, "src", meta.MergeBase)
|
||||||
c.Data["RawPath"] = conf.Server.Subpath + "/" + path.Join(headTarget, "raw", headCommitID)
|
c.Data["RawPath"] = conf.Server.Subpath + "/" + path.Join(headTarget, "raw", headCommitID)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -625,7 +629,7 @@ func CompareAndPullRequest(c *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
nothingToCompare := PrepareCompareDiff(c, headUser, headRepo, headGitRepo, prInfo, baseBranch, headBranch)
|
nothingToCompare := PrepareCompareDiff(c, headUser, headRepo, headGitRepo, prInfo, headBranch)
|
||||||
if c.Written() {
|
if c.Written() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -667,7 +671,7 @@ func CompareAndPullRequestPost(c *context.Context, f form.NewIssue) {
|
|||||||
attachments []string
|
attachments []string
|
||||||
)
|
)
|
||||||
|
|
||||||
headUser, headRepo, headGitRepo, prInfo, baseBranch, headBranch := ParseCompareInfo(c)
|
headUser, headRepo, headGitRepo, meta, baseBranch, headBranch := ParseCompareInfo(c)
|
||||||
if c.Written() {
|
if c.Written() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -686,7 +690,7 @@ func CompareAndPullRequestPost(c *context.Context, f form.NewIssue) {
|
|||||||
|
|
||||||
// This stage is already stop creating new pull request, so it does not matter if it has
|
// This stage is already stop creating new pull request, so it does not matter if it has
|
||||||
// something to compare or not.
|
// something to compare or not.
|
||||||
PrepareCompareDiff(c, headUser, headRepo, headGitRepo, prInfo, baseBranch, headBranch)
|
PrepareCompareDiff(c, headUser, headRepo, headGitRepo, meta, headBranch)
|
||||||
if c.Written() {
|
if c.Written() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -695,9 +699,9 @@ func CompareAndPullRequestPost(c *context.Context, f form.NewIssue) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
patch, err := headGitRepo.GetPatch(prInfo.MergeBase, headBranch)
|
patch, err := headGitRepo.DiffBinary(meta.MergeBase, headBranch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ServerError("GetPatch", err)
|
c.ServerError("get patch", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -720,7 +724,7 @@ func CompareAndPullRequestPost(c *context.Context, f form.NewIssue) {
|
|||||||
BaseBranch: baseBranch,
|
BaseBranch: baseBranch,
|
||||||
HeadRepo: headRepo,
|
HeadRepo: headRepo,
|
||||||
BaseRepo: repo,
|
BaseRepo: repo,
|
||||||
MergeBase: prInfo.MergeBase,
|
MergeBase: meta.MergeBase,
|
||||||
Type: db.PULL_REQUEST_GOGS,
|
Type: db.PULL_REQUEST_GOGS,
|
||||||
}
|
}
|
||||||
// FIXME: check error in the case two people send pull request at almost same time, give nice error prompt
|
// FIXME: check error in the case two people send pull request at almost same time, give nice error prompt
|
||||||
|
|||||||
@@ -8,13 +8,15 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gogs/git-module"
|
||||||
log "unknwon.dev/clog/v2"
|
log "unknwon.dev/clog/v2"
|
||||||
|
|
||||||
|
"gogs.io/gogs/internal/conf"
|
||||||
"gogs.io/gogs/internal/context"
|
"gogs.io/gogs/internal/context"
|
||||||
"gogs.io/gogs/internal/db"
|
"gogs.io/gogs/internal/db"
|
||||||
"gogs.io/gogs/internal/form"
|
"gogs.io/gogs/internal/form"
|
||||||
|
"gogs.io/gogs/internal/gitutil"
|
||||||
"gogs.io/gogs/internal/markup"
|
"gogs.io/gogs/internal/markup"
|
||||||
"gogs.io/gogs/internal/conf"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -26,14 +28,14 @@ const (
|
|||||||
func calReleaseNumCommitsBehind(repoCtx *context.Repository, release *db.Release, countCache map[string]int64) error {
|
func calReleaseNumCommitsBehind(repoCtx *context.Repository, release *db.Release, countCache map[string]int64) error {
|
||||||
// Get count if not exists
|
// Get count if not exists
|
||||||
if _, ok := countCache[release.Target]; !ok {
|
if _, ok := countCache[release.Target]; !ok {
|
||||||
if repoCtx.GitRepo.IsBranchExist(release.Target) {
|
if repoCtx.GitRepo.HasBranch(release.Target) {
|
||||||
commit, err := repoCtx.GitRepo.GetBranchCommit(release.Target)
|
commit, err := repoCtx.GitRepo.BranchCommit(release.Target)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("GetBranchCommit: %v", err)
|
return fmt.Errorf("get branch commit: %v", err)
|
||||||
}
|
}
|
||||||
countCache[release.Target], err = commit.CommitsCount()
|
countCache[release.Target], err = commit.CommitsCount()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("CommitsCount: %v", err)
|
return fmt.Errorf("count commits: %v", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Use NumCommits of the newest release on that target
|
// Use NumCommits of the newest release on that target
|
||||||
@@ -49,13 +51,13 @@ func Releases(c *context.Context) {
|
|||||||
c.Data["PageIsViewFiles"] = true
|
c.Data["PageIsViewFiles"] = true
|
||||||
c.Data["PageIsReleaseList"] = true
|
c.Data["PageIsReleaseList"] = true
|
||||||
|
|
||||||
tagsResult, err := c.Repo.GitRepo.GetTagsAfter(c.Query("after"), 10)
|
tagsPage, err := gitutil.Module.ListTagsAfter(c.Repo.GitRepo.Path(), c.Query("after"), 10)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Handle(500, fmt.Sprintf("GetTags '%s'", c.Repo.Repository.RepoPath()), err)
|
c.ServerError("get tags", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
releases, err := db.GetPublishedReleasesByRepoID(c.Repo.Repository.ID, tagsResult.Tags...)
|
releases, err := db.GetPublishedReleasesByRepoID(c.Repo.Repository.ID, tagsPage.Tags...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Handle(500, "GetPublishedReleasesByRepoID", err)
|
c.Handle(500, "GetPublishedReleasesByRepoID", err)
|
||||||
return
|
return
|
||||||
@@ -64,8 +66,8 @@ func Releases(c *context.Context) {
|
|||||||
// Temproray cache commits count of used branches to speed up.
|
// Temproray cache commits count of used branches to speed up.
|
||||||
countCache := make(map[string]int64)
|
countCache := make(map[string]int64)
|
||||||
|
|
||||||
results := make([]*db.Release, len(tagsResult.Tags))
|
results := make([]*db.Release, len(tagsPage.Tags))
|
||||||
for i, rawTag := range tagsResult.Tags {
|
for i, rawTag := range tagsPage.Tags {
|
||||||
for j, r := range releases {
|
for j, r := range releases {
|
||||||
if r == nil || r.TagName != rawTag {
|
if r == nil || r.TagName != rawTag {
|
||||||
continue
|
continue
|
||||||
@@ -89,9 +91,9 @@ func Releases(c *context.Context) {
|
|||||||
|
|
||||||
// No published release matches this tag
|
// No published release matches this tag
|
||||||
if results[i] == nil {
|
if results[i] == nil {
|
||||||
commit, err := c.Repo.GitRepo.GetTagCommit(rawTag)
|
commit, err := c.Repo.GitRepo.TagCommit(rawTag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Handle(500, "GetTagCommit", err)
|
c.Handle(500, "get tag commit", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,7 +105,7 @@ func Releases(c *context.Context) {
|
|||||||
|
|
||||||
results[i].NumCommits, err = commit.CommitsCount()
|
results[i].NumCommits, err = commit.CommitsCount()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Handle(500, "CommitsCount", err)
|
c.ServerError("count commits", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
results[i].NumCommitsBehind = c.Repo.CommitsCount - results[i].NumCommits
|
results[i].NumCommitsBehind = c.Repo.CommitsCount - results[i].NumCommits
|
||||||
@@ -113,7 +115,7 @@ func Releases(c *context.Context) {
|
|||||||
|
|
||||||
// Only show drafts if user is viewing the latest page
|
// Only show drafts if user is viewing the latest page
|
||||||
var drafts []*db.Release
|
var drafts []*db.Release
|
||||||
if tagsResult.HasLatest {
|
if tagsPage.HasLatest {
|
||||||
drafts, err = db.GetDraftReleasesByRepoID(c.Repo.Repository.ID)
|
drafts, err = db.GetDraftReleasesByRepoID(c.Repo.Repository.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Handle(500, "GetDraftReleasesByRepoID", err)
|
c.Handle(500, "GetDraftReleasesByRepoID", err)
|
||||||
@@ -140,9 +142,9 @@ func Releases(c *context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
c.Data["Releases"] = results
|
c.Data["Releases"] = results
|
||||||
c.Data["HasPrevious"] = !tagsResult.HasLatest
|
c.Data["HasPrevious"] = !tagsPage.HasLatest
|
||||||
c.Data["ReachEnd"] = tagsResult.ReachEnd
|
c.Data["ReachEnd"] = !tagsPage.HasNext
|
||||||
c.Data["PreviousAfter"] = tagsResult.PreviousAfter
|
c.Data["PreviousAfter"] = tagsPage.PreviousAfter
|
||||||
if len(results) > 0 {
|
if len(results) > 0 {
|
||||||
c.Data["NextAfter"] = results[len(results)-1].TagName
|
c.Data["NextAfter"] = results[len(results)-1].TagName
|
||||||
}
|
}
|
||||||
@@ -175,14 +177,14 @@ func NewReleasePost(c *context.Context, f form.NewRelease) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !c.Repo.GitRepo.IsBranchExist(f.Target) {
|
if !c.Repo.GitRepo.HasBranch(f.Target) {
|
||||||
c.RenderWithErr(c.Tr("form.target_branch_not_exist"), RELEASE_NEW, &f)
|
c.RenderWithErr(c.Tr("form.target_branch_not_exist"), RELEASE_NEW, &f)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use current time if tag not yet exist, otherwise get time from Git
|
// Use current time if tag not yet exist, otherwise get time from Git
|
||||||
var tagCreatedUnix int64
|
var tagCreatedUnix int64
|
||||||
tag, err := c.Repo.GitRepo.GetTag(f.TagName)
|
tag, err := c.Repo.GitRepo.Tag(git.RefsTags + f.TagName)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
commit, err := tag.Commit()
|
commit, err := tag.Commit()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -190,15 +192,15 @@ func NewReleasePost(c *context.Context, f form.NewRelease) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
commit, err := c.Repo.GitRepo.GetBranchCommit(f.Target)
|
commit, err := c.Repo.GitRepo.BranchCommit(f.Target)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Handle(500, "GetBranchCommit", err)
|
c.ServerError("get branch commit", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
commitsCount, err := commit.CommitsCount()
|
commitsCount, err := commit.CommitsCount()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Handle(500, "CommitsCount", err)
|
c.ServerError("count commits", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/unknwon/com"
|
"github.com/unknwon/com"
|
||||||
@@ -275,18 +276,18 @@ func Download(c *context.Context) {
|
|||||||
refName string
|
refName string
|
||||||
ext string
|
ext string
|
||||||
archivePath string
|
archivePath string
|
||||||
archiveType git.ArchiveType
|
archiveFormat git.ArchiveFormat
|
||||||
)
|
)
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case strings.HasSuffix(uri, ".zip"):
|
case strings.HasSuffix(uri, ".zip"):
|
||||||
ext = ".zip"
|
ext = ".zip"
|
||||||
archivePath = path.Join(c.Repo.GitRepo.Path, "archives/zip")
|
archivePath = filepath.Join(c.Repo.GitRepo.Path(), "archives", "zip")
|
||||||
archiveType = git.ZIP
|
archiveFormat = git.ArchiveZip
|
||||||
case strings.HasSuffix(uri, ".tar.gz"):
|
case strings.HasSuffix(uri, ".tar.gz"):
|
||||||
ext = ".tar.gz"
|
ext = ".tar.gz"
|
||||||
archivePath = path.Join(c.Repo.GitRepo.Path, "archives/targz")
|
archivePath = filepath.Join(c.Repo.GitRepo.Path(), "archives", "targz")
|
||||||
archiveType = git.TARGZ
|
archiveFormat = git.ArchiveTarGz
|
||||||
default:
|
default:
|
||||||
log.Trace("Unknown format: %s", uri)
|
log.Trace("Unknown format: %s", uri)
|
||||||
c.Error(404)
|
c.Error(404)
|
||||||
@@ -307,20 +308,20 @@ func Download(c *context.Context) {
|
|||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
gitRepo := c.Repo.GitRepo
|
gitRepo := c.Repo.GitRepo
|
||||||
if gitRepo.IsBranchExist(refName) {
|
if gitRepo.HasBranch(refName) {
|
||||||
commit, err = gitRepo.GetBranchCommit(refName)
|
commit, err = gitRepo.BranchCommit(refName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Handle(500, "GetBranchCommit", err)
|
c.ServerError("get branch commit", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else if gitRepo.IsTagExist(refName) {
|
} else if gitRepo.HasTag(refName) {
|
||||||
commit, err = gitRepo.GetTagCommit(refName)
|
commit, err = gitRepo.TagCommit(refName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Handle(500, "GetTagCommit", err)
|
c.ServerError("get tag commit", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else if len(refName) >= 7 && len(refName) <= 40 {
|
} else if len(refName) >= 7 && len(refName) <= 40 {
|
||||||
commit, err = gitRepo.GetCommit(refName)
|
commit, err = gitRepo.CatFileCommit(refName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.NotFound()
|
c.NotFound()
|
||||||
return
|
return
|
||||||
@@ -332,8 +333,8 @@ func Download(c *context.Context) {
|
|||||||
|
|
||||||
archivePath = path.Join(archivePath, tool.ShortSHA1(commit.ID.String())+ext)
|
archivePath = path.Join(archivePath, tool.ShortSHA1(commit.ID.String())+ext)
|
||||||
if !com.IsFile(archivePath) {
|
if !com.IsFile(archivePath) {
|
||||||
if err := commit.CreateArchive(archivePath, archiveType); err != nil {
|
if err := commit.CreateArchive(archiveFormat, archivePath); err != nil {
|
||||||
c.Handle(500, "Download -> CreateArchive "+archivePath, err)
|
c.ServerError("creates archive", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ package repo
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -448,7 +449,7 @@ func SettingsBranches(c *context.Context) {
|
|||||||
// Filter out deleted branches
|
// Filter out deleted branches
|
||||||
branches := make([]string, 0, len(protectBranches))
|
branches := make([]string, 0, len(protectBranches))
|
||||||
for i := range protectBranches {
|
for i := range protectBranches {
|
||||||
if c.Repo.GitRepo.IsBranchExist(protectBranches[i].Name) {
|
if c.Repo.GitRepo.HasBranch(protectBranches[i].Name) {
|
||||||
branches = append(branches, protectBranches[i].Name)
|
branches = append(branches, protectBranches[i].Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -459,15 +460,12 @@ func SettingsBranches(c *context.Context) {
|
|||||||
|
|
||||||
func UpdateDefaultBranch(c *context.Context) {
|
func UpdateDefaultBranch(c *context.Context) {
|
||||||
branch := c.Query("branch")
|
branch := c.Query("branch")
|
||||||
if c.Repo.GitRepo.IsBranchExist(branch) &&
|
if c.Repo.GitRepo.HasBranch(branch) &&
|
||||||
c.Repo.Repository.DefaultBranch != branch {
|
c.Repo.Repository.DefaultBranch != branch {
|
||||||
c.Repo.Repository.DefaultBranch = branch
|
c.Repo.Repository.DefaultBranch = branch
|
||||||
if err := c.Repo.GitRepo.SetDefaultBranch(branch); err != nil {
|
if _, err := c.Repo.GitRepo.SymbolicRef(git.SymbolicRefOptions{
|
||||||
if !git.IsErrUnsupportedVersion(err) {
|
Ref: git.RefsHeads + branch,
|
||||||
c.Handle(500, "SetDefaultBranch", err)
|
}); err != nil {
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Flash.Warning(c.Tr("repo.settings.update_default_branch_unsupported"))
|
c.Flash.Warning(c.Tr("repo.settings.update_default_branch_unsupported"))
|
||||||
c.Redirect(c.Repo.RepoLink + "/settings/branches")
|
c.Redirect(c.Repo.RepoLink + "/settings/branches")
|
||||||
return
|
return
|
||||||
@@ -485,7 +483,7 @@ func UpdateDefaultBranch(c *context.Context) {
|
|||||||
|
|
||||||
func SettingsProtectedBranch(c *context.Context) {
|
func SettingsProtectedBranch(c *context.Context) {
|
||||||
branch := c.Params("*")
|
branch := c.Params("*")
|
||||||
if !c.Repo.GitRepo.IsBranchExist(branch) {
|
if !c.Repo.GitRepo.HasBranch(branch) {
|
||||||
c.NotFound()
|
c.NotFound()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -530,7 +528,7 @@ func SettingsProtectedBranch(c *context.Context) {
|
|||||||
|
|
||||||
func SettingsProtectedBranchPost(c *context.Context, f form.ProtectBranch) {
|
func SettingsProtectedBranchPost(c *context.Context, f form.ProtectBranch) {
|
||||||
branch := c.Params("*")
|
branch := c.Params("*")
|
||||||
if !c.Repo.GitRepo.IsBranchExist(branch) {
|
if !c.Repo.GitRepo.HasBranch(branch) {
|
||||||
c.NotFound()
|
c.NotFound()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -570,7 +568,7 @@ func SettingsGitHooks(c *context.Context) {
|
|||||||
c.Data["Title"] = c.Tr("repo.settings.githooks")
|
c.Data["Title"] = c.Tr("repo.settings.githooks")
|
||||||
c.Data["PageIsSettingsGitHooks"] = true
|
c.Data["PageIsSettingsGitHooks"] = true
|
||||||
|
|
||||||
hooks, err := c.Repo.GitRepo.Hooks()
|
hooks, err := c.Repo.GitRepo.Hooks("custom_hooks")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Handle(500, "Hooks", err)
|
c.Handle(500, "Hooks", err)
|
||||||
return
|
return
|
||||||
@@ -586,9 +584,9 @@ func SettingsGitHooksEdit(c *context.Context) {
|
|||||||
c.Data["RequireSimpleMDE"] = true
|
c.Data["RequireSimpleMDE"] = true
|
||||||
|
|
||||||
name := c.Params(":name")
|
name := c.Params(":name")
|
||||||
hook, err := c.Repo.GitRepo.GetHook(name)
|
hook, err := c.Repo.GitRepo.Hook("custom_hooks", git.HookName(name))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == git.ErrNotValidHook {
|
if err == os.ErrNotExist {
|
||||||
c.Handle(404, "GetHook", err)
|
c.Handle(404, "GetHook", err)
|
||||||
} else {
|
} else {
|
||||||
c.Handle(500, "GetHook", err)
|
c.Handle(500, "GetHook", err)
|
||||||
@@ -601,17 +599,16 @@ func SettingsGitHooksEdit(c *context.Context) {
|
|||||||
|
|
||||||
func SettingsGitHooksEditPost(c *context.Context) {
|
func SettingsGitHooksEditPost(c *context.Context) {
|
||||||
name := c.Params(":name")
|
name := c.Params(":name")
|
||||||
hook, err := c.Repo.GitRepo.GetHook(name)
|
hook, err := c.Repo.GitRepo.Hook("custom_hooks", git.HookName(name))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == git.ErrNotValidHook {
|
if err == os.ErrNotExist {
|
||||||
c.Handle(404, "GetHook", err)
|
c.Handle(404, "GetHook", err)
|
||||||
} else {
|
} else {
|
||||||
c.Handle(500, "GetHook", err)
|
c.Handle(500, "GetHook", err)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
hook.Content = c.Query("content")
|
if err = hook.Update(c.Query("content")); err != nil {
|
||||||
if err = hook.Update(); err != nil {
|
|
||||||
c.Handle(500, "hook.Update", err)
|
c.Handle(500, "hook.Update", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,19 +8,20 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
gotemplate "html/template"
|
gotemplate "html/template"
|
||||||
"io/ioutil"
|
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gogs/git-module"
|
||||||
|
"github.com/pkg/errors"
|
||||||
"github.com/unknwon/paginater"
|
"github.com/unknwon/paginater"
|
||||||
log "unknwon.dev/clog/v2"
|
log "unknwon.dev/clog/v2"
|
||||||
|
|
||||||
"github.com/gogs/git-module"
|
"gogs.io/gogs/internal/conf"
|
||||||
|
|
||||||
"gogs.io/gogs/internal/context"
|
"gogs.io/gogs/internal/context"
|
||||||
"gogs.io/gogs/internal/db"
|
"gogs.io/gogs/internal/db"
|
||||||
|
"gogs.io/gogs/internal/gitutil"
|
||||||
"gogs.io/gogs/internal/markup"
|
"gogs.io/gogs/internal/markup"
|
||||||
"gogs.io/gogs/internal/conf"
|
|
||||||
"gogs.io/gogs/internal/template"
|
"gogs.io/gogs/internal/template"
|
||||||
"gogs.io/gogs/internal/template/highlight"
|
"gogs.io/gogs/internal/template/highlight"
|
||||||
"gogs.io/gogs/internal/tool"
|
"gogs.io/gogs/internal/tool"
|
||||||
@@ -34,32 +35,36 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func renderDirectory(c *context.Context, treeLink string) {
|
func renderDirectory(c *context.Context, treeLink string) {
|
||||||
tree, err := c.Repo.Commit.SubTree(c.Repo.TreePath)
|
tree, err := c.Repo.Commit.Subtree(c.Repo.TreePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.NotFoundOrServerError("Repo.Commit.SubTree", git.IsErrNotExist, err)
|
c.NotFoundOrServerError("get subtree", gitutil.IsErrRevisionNotExist, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
entries, err := tree.ListEntries()
|
entries, err := tree.Entries()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ServerError("ListEntries", err)
|
c.ServerError("list entries", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
entries.Sort()
|
entries.Sort()
|
||||||
|
|
||||||
c.Data["Files"], err = entries.GetCommitsInfoWithCustomConcurrency(c.Repo.Commit, c.Repo.TreePath, conf.Repository.CommitsFetchConcurrency)
|
c.Data["Files"], err = entries.CommitsInfo(c.Repo.Commit, git.CommitsInfoOptions{
|
||||||
|
Path: c.Repo.TreePath,
|
||||||
|
MaxConcurrency: conf.Repository.CommitsFetchConcurrency,
|
||||||
|
Timeout: 5 * time.Minute,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ServerError("GetCommitsInfoWithCustomConcurrency", err)
|
c.ServerError("get commits info", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var readmeFile *git.Blob
|
var readmeFile *git.Blob
|
||||||
for _, entry := range entries {
|
for _, entry := range entries {
|
||||||
if entry.IsDir() || !markup.IsReadmeFile(entry.Name()) {
|
if entry.IsTree() || !markup.IsReadmeFile(entry.Name()) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: collect all possible README files and show with priority.
|
// TODO(unknwon): collect all possible README files and show with priority.
|
||||||
readmeFile = entry.Blob()
|
readmeFile = entry.Blob()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -69,37 +74,30 @@ func renderDirectory(c *context.Context, treeLink string) {
|
|||||||
c.Data["ReadmeInList"] = true
|
c.Data["ReadmeInList"] = true
|
||||||
c.Data["ReadmeExist"] = true
|
c.Data["ReadmeExist"] = true
|
||||||
|
|
||||||
dataRc, err := readmeFile.Data()
|
p, err := readmeFile.Bytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ServerError("readmeFile.Data", err)
|
c.ServerError("readmeFile.Data", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := make([]byte, 1024)
|
isTextFile := tool.IsTextFile(p)
|
||||||
n, _ := dataRc.Read(buf)
|
|
||||||
buf = buf[:n]
|
|
||||||
|
|
||||||
isTextFile := tool.IsTextFile(buf)
|
|
||||||
c.Data["IsTextFile"] = isTextFile
|
c.Data["IsTextFile"] = isTextFile
|
||||||
c.Data["FileName"] = readmeFile.Name()
|
c.Data["FileName"] = readmeFile.Name()
|
||||||
if isTextFile {
|
if isTextFile {
|
||||||
d, _ := ioutil.ReadAll(dataRc)
|
|
||||||
buf = append(buf, d...)
|
|
||||||
|
|
||||||
switch markup.Detect(readmeFile.Name()) {
|
switch markup.Detect(readmeFile.Name()) {
|
||||||
case markup.MARKDOWN:
|
case markup.MARKDOWN:
|
||||||
c.Data["IsMarkdown"] = true
|
c.Data["IsMarkdown"] = true
|
||||||
buf = markup.Markdown(buf, treeLink, c.Repo.Repository.ComposeMetas())
|
p = markup.Markdown(p, treeLink, c.Repo.Repository.ComposeMetas())
|
||||||
case markup.ORG_MODE:
|
case markup.ORG_MODE:
|
||||||
c.Data["IsMarkdown"] = true
|
c.Data["IsMarkdown"] = true
|
||||||
buf = markup.OrgMode(buf, treeLink, c.Repo.Repository.ComposeMetas())
|
p = markup.OrgMode(p, treeLink, c.Repo.Repository.ComposeMetas())
|
||||||
case markup.IPYTHON_NOTEBOOK:
|
case markup.IPYTHON_NOTEBOOK:
|
||||||
c.Data["IsIPythonNotebook"] = true
|
c.Data["IsIPythonNotebook"] = true
|
||||||
c.Data["RawFileLink"] = c.Repo.RepoLink + "/raw/" + path.Join(c.Repo.BranchName, c.Repo.TreePath, readmeFile.Name())
|
c.Data["RawFileLink"] = c.Repo.RepoLink + "/raw/" + path.Join(c.Repo.BranchName, c.Repo.TreePath, readmeFile.Name())
|
||||||
default:
|
default:
|
||||||
buf = bytes.Replace(buf, []byte("\n"), []byte(`<br>`), -1)
|
p = bytes.Replace(p, []byte("\n"), []byte(`<br>`), -1)
|
||||||
}
|
}
|
||||||
c.Data["FileContent"] = string(buf)
|
c.Data["FileContent"] = string(p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,9 +105,9 @@ func renderDirectory(c *context.Context, treeLink string) {
|
|||||||
// or of directory if not in root directory.
|
// or of directory if not in root directory.
|
||||||
latestCommit := c.Repo.Commit
|
latestCommit := c.Repo.Commit
|
||||||
if len(c.Repo.TreePath) > 0 {
|
if len(c.Repo.TreePath) > 0 {
|
||||||
latestCommit, err = c.Repo.Commit.GetCommitByPath(c.Repo.TreePath)
|
latestCommit, err = c.Repo.Commit.CommitByPath(git.CommitByRevisionOptions{Path: c.Repo.TreePath})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ServerError("GetCommitByPath", err)
|
c.ServerError("get commit by path", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -126,7 +124,7 @@ func renderFile(c *context.Context, entry *git.TreeEntry, treeLink, rawLink stri
|
|||||||
c.Data["IsViewFile"] = true
|
c.Data["IsViewFile"] = true
|
||||||
|
|
||||||
blob := entry.Blob()
|
blob := entry.Blob()
|
||||||
dataRc, err := blob.Data()
|
p, err := blob.Bytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Handle(500, "Data", err)
|
c.Handle(500, "Data", err)
|
||||||
return
|
return
|
||||||
@@ -137,11 +135,7 @@ func renderFile(c *context.Context, entry *git.TreeEntry, treeLink, rawLink stri
|
|||||||
c.Data["HighlightClass"] = highlight.FileNameToHighlightClass(blob.Name())
|
c.Data["HighlightClass"] = highlight.FileNameToHighlightClass(blob.Name())
|
||||||
c.Data["RawFileLink"] = rawLink + "/" + c.Repo.TreePath
|
c.Data["RawFileLink"] = rawLink + "/" + c.Repo.TreePath
|
||||||
|
|
||||||
buf := make([]byte, 1024)
|
isTextFile := tool.IsTextFile(p)
|
||||||
n, _ := dataRc.Read(buf)
|
|
||||||
buf = buf[:n]
|
|
||||||
|
|
||||||
isTextFile := tool.IsTextFile(buf)
|
|
||||||
c.Data["IsTextFile"] = isTextFile
|
c.Data["IsTextFile"] = isTextFile
|
||||||
|
|
||||||
// Assume file is not editable first.
|
// Assume file is not editable first.
|
||||||
@@ -159,26 +153,23 @@ func renderFile(c *context.Context, entry *git.TreeEntry, treeLink, rawLink stri
|
|||||||
|
|
||||||
c.Data["ReadmeExist"] = markup.IsReadmeFile(blob.Name())
|
c.Data["ReadmeExist"] = markup.IsReadmeFile(blob.Name())
|
||||||
|
|
||||||
d, _ := ioutil.ReadAll(dataRc)
|
|
||||||
buf = append(buf, d...)
|
|
||||||
|
|
||||||
switch markup.Detect(blob.Name()) {
|
switch markup.Detect(blob.Name()) {
|
||||||
case markup.MARKDOWN:
|
case markup.MARKDOWN:
|
||||||
c.Data["IsMarkdown"] = true
|
c.Data["IsMarkdown"] = true
|
||||||
c.Data["FileContent"] = string(markup.Markdown(buf, path.Dir(treeLink), c.Repo.Repository.ComposeMetas()))
|
c.Data["FileContent"] = string(markup.Markdown(p, path.Dir(treeLink), c.Repo.Repository.ComposeMetas()))
|
||||||
case markup.ORG_MODE:
|
case markup.ORG_MODE:
|
||||||
c.Data["IsMarkdown"] = true
|
c.Data["IsMarkdown"] = true
|
||||||
c.Data["FileContent"] = string(markup.OrgMode(buf, path.Dir(treeLink), c.Repo.Repository.ComposeMetas()))
|
c.Data["FileContent"] = string(markup.OrgMode(p, path.Dir(treeLink), c.Repo.Repository.ComposeMetas()))
|
||||||
case markup.IPYTHON_NOTEBOOK:
|
case markup.IPYTHON_NOTEBOOK:
|
||||||
c.Data["IsIPythonNotebook"] = true
|
c.Data["IsIPythonNotebook"] = true
|
||||||
default:
|
default:
|
||||||
// Building code view blocks with line number on server side.
|
// Building code view blocks with line number on server side.
|
||||||
var fileContent string
|
var fileContent string
|
||||||
if err, content := template.ToUTF8WithErr(buf); err != nil {
|
if err, content := template.ToUTF8WithErr(p); err != nil {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("ToUTF8WithErr: %s", err)
|
log.Error("ToUTF8WithErr: %s", err)
|
||||||
}
|
}
|
||||||
fileContent = string(buf)
|
fileContent = string(p)
|
||||||
} else {
|
} else {
|
||||||
fileContent = content
|
fileContent = content
|
||||||
}
|
}
|
||||||
@@ -210,11 +201,11 @@ func renderFile(c *context.Context, entry *git.TreeEntry, treeLink, rawLink stri
|
|||||||
c.Data["EditFileTooltip"] = c.Tr("repo.editor.fork_before_edit")
|
c.Data["EditFileTooltip"] = c.Tr("repo.editor.fork_before_edit")
|
||||||
}
|
}
|
||||||
|
|
||||||
case tool.IsPDFFile(buf):
|
case tool.IsPDFFile(p):
|
||||||
c.Data["IsPDFFile"] = true
|
c.Data["IsPDFFile"] = true
|
||||||
case tool.IsVideoFile(buf):
|
case tool.IsVideoFile(p):
|
||||||
c.Data["IsVideoFile"] = true
|
c.Data["IsVideoFile"] = true
|
||||||
case tool.IsImageFile(buf):
|
case tool.IsImageFile(p):
|
||||||
c.Data["IsImageFile"] = true
|
c.Data["IsImageFile"] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,9 +220,9 @@ func renderFile(c *context.Context, entry *git.TreeEntry, treeLink, rawLink stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setEditorconfigIfExists(c *context.Context) {
|
func setEditorconfigIfExists(c *context.Context) {
|
||||||
ec, err := c.Repo.GetEditorconfig()
|
ec, err := c.Repo.Editorconfig()
|
||||||
if err != nil && !git.IsErrNotExist(err) {
|
if err != nil && !gitutil.IsErrRevisionNotExist(errors.Cause(err)) {
|
||||||
log.Trace("setEditorconfigIfExists.GetEditorconfig [%d]: %v", c.Repo.Repository.ID, err)
|
log.Warn("setEditorconfigIfExists.Editorconfig [repo_id: %d]: %v", c.Repo.Repository.ID, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.Data["Editorconfig"] = ec
|
c.Data["Editorconfig"] = ec
|
||||||
@@ -277,13 +268,13 @@ func Home(c *context.Context) {
|
|||||||
c.Data["PageIsRepoHome"] = isRootDir
|
c.Data["PageIsRepoHome"] = isRootDir
|
||||||
|
|
||||||
// Get current entry user currently looking at.
|
// Get current entry user currently looking at.
|
||||||
entry, err := c.Repo.Commit.GetTreeEntryByPath(c.Repo.TreePath)
|
entry, err := c.Repo.Commit.TreeEntry(c.Repo.TreePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.NotFoundOrServerError("Repo.Commit.GetTreeEntryByPath", git.IsErrNotExist, err)
|
c.NotFoundOrServerError("get tree entry", gitutil.IsErrRevisionNotExist, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if entry.IsDir() {
|
if entry.IsTree() {
|
||||||
renderDirectory(c, treeLink)
|
renderDirectory(c, treeLink)
|
||||||
} else {
|
} else {
|
||||||
renderFile(c, entry, treeLink, rawLink)
|
renderFile(c, entry, treeLink, rawLink)
|
||||||
|
|||||||
@@ -14,11 +14,11 @@ import (
|
|||||||
git "github.com/gogs/git-module"
|
git "github.com/gogs/git-module"
|
||||||
api "github.com/gogs/go-gogs-client"
|
api "github.com/gogs/go-gogs-client"
|
||||||
|
|
||||||
|
"gogs.io/gogs/internal/conf"
|
||||||
"gogs.io/gogs/internal/context"
|
"gogs.io/gogs/internal/context"
|
||||||
"gogs.io/gogs/internal/db"
|
"gogs.io/gogs/internal/db"
|
||||||
"gogs.io/gogs/internal/db/errors"
|
"gogs.io/gogs/internal/db/errors"
|
||||||
"gogs.io/gogs/internal/form"
|
"gogs.io/gogs/internal/form"
|
||||||
"gogs.io/gogs/internal/conf"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -517,23 +517,37 @@ func DingtalkHooksEditPost(c *context.Context, f form.NewDingtalkHook) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestWebhook(c *context.Context) {
|
func TestWebhook(c *context.Context) {
|
||||||
var authorUsername, committerUsername string
|
|
||||||
|
var (
|
||||||
|
commitID string
|
||||||
|
commitMessage string
|
||||||
|
author *git.Signature
|
||||||
|
committer *git.Signature
|
||||||
|
authorUsername string
|
||||||
|
committerUsername string
|
||||||
|
nameStatus *git.NameStatus
|
||||||
|
)
|
||||||
|
|
||||||
// Grab latest commit or fake one if it's empty repository.
|
// Grab latest commit or fake one if it's empty repository.
|
||||||
commit := c.Repo.Commit
|
|
||||||
if commit == nil {
|
if c.Repo.Commit == nil {
|
||||||
|
commitID = git.EmptyID
|
||||||
|
commitMessage = "This is a fake commit"
|
||||||
ghost := db.NewGhostUser()
|
ghost := db.NewGhostUser()
|
||||||
commit = &git.Commit{
|
author = ghost.NewGitSig()
|
||||||
ID: git.MustIDFromString(git.EMPTY_SHA),
|
committer = ghost.NewGitSig()
|
||||||
Author: ghost.NewGitSig(),
|
|
||||||
Committer: ghost.NewGitSig(),
|
|
||||||
CommitMessage: "This is a fake commit",
|
|
||||||
}
|
|
||||||
authorUsername = ghost.Name
|
authorUsername = ghost.Name
|
||||||
committerUsername = ghost.Name
|
committerUsername = ghost.Name
|
||||||
|
nameStatus = &git.NameStatus{}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
commitID = c.Repo.Commit.ID.String()
|
||||||
|
commitMessage = c.Repo.Commit.Message
|
||||||
|
author = c.Repo.Commit.Author
|
||||||
|
committer = c.Repo.Commit.Committer
|
||||||
|
|
||||||
// Try to match email with a real user.
|
// Try to match email with a real user.
|
||||||
author, err := db.GetUserByEmail(commit.Author.Email)
|
author, err := db.GetUserByEmail(c.Repo.Commit.Author.Email)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
authorUsername = author.Name
|
authorUsername = author.Name
|
||||||
} else if !errors.IsUserNotExist(err) {
|
} else if !errors.IsUserNotExist(err) {
|
||||||
@@ -541,44 +555,44 @@ func TestWebhook(c *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
committer, err := db.GetUserByEmail(commit.Committer.Email)
|
user, err := db.GetUserByEmail(c.Repo.Commit.Committer.Email)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
committerUsername = committer.Name
|
committerUsername = user.Name
|
||||||
} else if !errors.IsUserNotExist(err) {
|
} else if !errors.IsUserNotExist(err) {
|
||||||
c.Handle(500, "GetUserByEmail.(committer)", err)
|
c.Handle(500, "GetUserByEmail.(committer)", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fileStatus, err := commit.FileStatus()
|
nameStatus, err = c.Repo.Commit.ShowNameStatus()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Handle(500, "FileStatus", err)
|
c.Handle(500, "FileStatus", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
apiUser := c.User.APIFormat()
|
apiUser := c.User.APIFormat()
|
||||||
p := &api.PushPayload{
|
p := &api.PushPayload{
|
||||||
Ref: git.BRANCH_PREFIX + c.Repo.Repository.DefaultBranch,
|
Ref: git.RefsHeads + c.Repo.Repository.DefaultBranch,
|
||||||
Before: commit.ID.String(),
|
Before: commitID,
|
||||||
After: commit.ID.String(),
|
After: commitID,
|
||||||
Commits: []*api.PayloadCommit{
|
Commits: []*api.PayloadCommit{
|
||||||
{
|
{
|
||||||
ID: commit.ID.String(),
|
ID: commitID,
|
||||||
Message: commit.Message(),
|
Message: commitMessage,
|
||||||
URL: c.Repo.Repository.HTMLURL() + "/commit/" + commit.ID.String(),
|
URL: c.Repo.Repository.HTMLURL() + "/commit/" + commitID,
|
||||||
Author: &api.PayloadUser{
|
Author: &api.PayloadUser{
|
||||||
Name: commit.Author.Name,
|
Name: author.Name,
|
||||||
Email: commit.Author.Email,
|
Email: author.Email,
|
||||||
UserName: authorUsername,
|
UserName: authorUsername,
|
||||||
},
|
},
|
||||||
Committer: &api.PayloadUser{
|
Committer: &api.PayloadUser{
|
||||||
Name: commit.Committer.Name,
|
Name: committer.Name,
|
||||||
Email: commit.Committer.Email,
|
Email: committer.Email,
|
||||||
UserName: committerUsername,
|
UserName: committerUsername,
|
||||||
},
|
},
|
||||||
Added: fileStatus.Added,
|
Added: nameStatus.Added,
|
||||||
Removed: fileStatus.Removed,
|
Removed: nameStatus.Removed,
|
||||||
Modified: fileStatus.Modified,
|
Modified: nameStatus.Modified,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Repo: c.Repo.Repository.APIFormat(nil),
|
Repo: c.Repo.Repository.APIFormat(nil),
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
package repo
|
package repo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -14,6 +13,7 @@ import (
|
|||||||
"gogs.io/gogs/internal/context"
|
"gogs.io/gogs/internal/context"
|
||||||
"gogs.io/gogs/internal/db"
|
"gogs.io/gogs/internal/db"
|
||||||
"gogs.io/gogs/internal/form"
|
"gogs.io/gogs/internal/form"
|
||||||
|
"gogs.io/gogs/internal/gitutil"
|
||||||
"gogs.io/gogs/internal/markup"
|
"gogs.io/gogs/internal/markup"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -43,27 +43,27 @@ type PageMeta struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func renderWikiPage(c *context.Context, isViewPage bool) (*git.Repository, string) {
|
func renderWikiPage(c *context.Context, isViewPage bool) (*git.Repository, string) {
|
||||||
wikiRepo, err := git.OpenRepository(c.Repo.Repository.WikiPath())
|
wikiRepo, err := git.Open(c.Repo.Repository.WikiPath())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Handle(500, "OpenRepository", err)
|
c.ServerError("open repository", err)
|
||||||
return nil, ""
|
return nil, ""
|
||||||
}
|
}
|
||||||
commit, err := wikiRepo.GetBranchCommit("master")
|
commit, err := wikiRepo.BranchCommit("master")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Handle(500, "GetBranchCommit", err)
|
c.ServerError("get branch commit", err)
|
||||||
return nil, ""
|
return nil, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get page list.
|
// Get page list.
|
||||||
if isViewPage {
|
if isViewPage {
|
||||||
entries, err := commit.ListEntries()
|
entries, err := commit.Entries()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Handle(500, "ListEntries", err)
|
c.ServerError("list entries", err)
|
||||||
return nil, ""
|
return nil, ""
|
||||||
}
|
}
|
||||||
pages := make([]PageMeta, 0, len(entries))
|
pages := make([]PageMeta, 0, len(entries))
|
||||||
for i := range entries {
|
for i := range entries {
|
||||||
if entries[i].Type == git.OBJECT_BLOB && strings.HasSuffix(entries[i].Name(), ".md") {
|
if entries[i].Type() == git.ObjectBlob && strings.HasSuffix(entries[i].Name(), ".md") {
|
||||||
name := strings.TrimSuffix(entries[i].Name(), ".md")
|
name := strings.TrimSuffix(entries[i].Name(), ".md")
|
||||||
pages = append(pages, PageMeta{
|
pages = append(pages, PageMeta{
|
||||||
Name: name,
|
Name: name,
|
||||||
@@ -86,29 +86,24 @@ func renderWikiPage(c *context.Context, isViewPage bool) (*git.Repository, strin
|
|||||||
c.Data["title"] = pageName
|
c.Data["title"] = pageName
|
||||||
c.Data["RequireHighlightJS"] = true
|
c.Data["RequireHighlightJS"] = true
|
||||||
|
|
||||||
blob, err := commit.GetBlobByPath(pageName + ".md")
|
blob, err := commit.Blob(pageName + ".md")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if git.IsErrNotExist(err) {
|
if gitutil.IsErrRevisionNotExist(err) {
|
||||||
c.Redirect(c.Repo.RepoLink + "/wiki/_pages")
|
c.Redirect(c.Repo.RepoLink + "/wiki/_pages")
|
||||||
} else {
|
} else {
|
||||||
c.Handle(500, "GetBlobByPath", err)
|
c.ServerError("GetBlobByPath", err)
|
||||||
}
|
}
|
||||||
return nil, ""
|
return nil, ""
|
||||||
}
|
}
|
||||||
r, err := blob.Data()
|
p, err := blob.Bytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Handle(500, "Data", err)
|
c.ServerError("Data", err)
|
||||||
return nil, ""
|
|
||||||
}
|
|
||||||
data, err := ioutil.ReadAll(r)
|
|
||||||
if err != nil {
|
|
||||||
c.Handle(500, "ReadAll", err)
|
|
||||||
return nil, ""
|
return nil, ""
|
||||||
}
|
}
|
||||||
if isViewPage {
|
if isViewPage {
|
||||||
c.Data["content"] = string(markup.Markdown(data, c.Repo.RepoLink, c.Repo.Repository.ComposeMetas()))
|
c.Data["content"] = string(markup.Markdown(p, c.Repo.RepoLink, c.Repo.Repository.ComposeMetas()))
|
||||||
} else {
|
} else {
|
||||||
c.Data["content"] = string(data)
|
c.Data["content"] = string(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
return wikiRepo, pageName
|
return wikiRepo, pageName
|
||||||
@@ -129,12 +124,12 @@ func Wiki(c *context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get last change information.
|
// Get last change information.
|
||||||
lastCommit, err := wikiRepo.GetCommitByPath(pageName + ".md")
|
commits, err := wikiRepo.Log(git.RefsHeads+"master", git.LogOptions{Path: pageName + ".md"})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Handle(500, "GetCommitByPath", err)
|
c.ServerError("get commits by path", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.Data["Author"] = lastCommit.Author
|
c.Data["Author"] = commits[0].Author
|
||||||
|
|
||||||
c.HTML(200, WIKI_VIEW)
|
c.HTML(200, WIKI_VIEW)
|
||||||
}
|
}
|
||||||
@@ -148,35 +143,35 @@ func WikiPages(c *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
wikiRepo, err := git.OpenRepository(c.Repo.Repository.WikiPath())
|
wikiRepo, err := git.Open(c.Repo.Repository.WikiPath())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Handle(500, "OpenRepository", err)
|
c.ServerError("open repository", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
commit, err := wikiRepo.GetBranchCommit("master")
|
commit, err := wikiRepo.BranchCommit("master")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Handle(500, "GetBranchCommit", err)
|
c.ServerError("get branch commit", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
entries, err := commit.ListEntries()
|
entries, err := commit.Entries()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Handle(500, "ListEntries", err)
|
c.ServerError("list entries", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
pages := make([]PageMeta, 0, len(entries))
|
pages := make([]PageMeta, 0, len(entries))
|
||||||
for i := range entries {
|
for i := range entries {
|
||||||
if entries[i].Type == git.OBJECT_BLOB && strings.HasSuffix(entries[i].Name(), ".md") {
|
if entries[i].Type() == git.ObjectBlob && strings.HasSuffix(entries[i].Name(), ".md") {
|
||||||
commit, err := wikiRepo.GetCommitByPath(entries[i].Name())
|
commits, err := wikiRepo.Log(git.RefsHeads+"master", git.LogOptions{Path: entries[i].Name()})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ServerError("GetCommitByPath", err)
|
c.ServerError("get commits by path", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
name := strings.TrimSuffix(entries[i].Name(), ".md")
|
name := strings.TrimSuffix(entries[i].Name(), ".md")
|
||||||
pages = append(pages, PageMeta{
|
pages = append(pages, PageMeta{
|
||||||
Name: name,
|
Name: name,
|
||||||
URL: db.ToWikiPageURL(name),
|
URL: db.ToWikiPageURL(name),
|
||||||
Updated: commit.Author.When,
|
Updated: commits[0].Author.When,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -212,7 +207,7 @@ func NewWikiPost(c *context.Context, f form.NewWiki) {
|
|||||||
c.Data["Err_Title"] = true
|
c.Data["Err_Title"] = true
|
||||||
c.RenderWithErr(c.Tr("repo.wiki.page_already_exists"), WIKI_NEW, &f)
|
c.RenderWithErr(c.Tr("repo.wiki.page_already_exists"), WIKI_NEW, &f)
|
||||||
} else {
|
} else {
|
||||||
c.Handle(500, "AddWikiPage", err)
|
c.ServerError("AddWikiPage", err)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -249,7 +244,7 @@ func EditWikiPost(c *context.Context, f form.NewWiki) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := c.Repo.Repository.EditWikiPage(c.User, f.OldTitle, f.Title, f.Content, f.Message); err != nil {
|
if err := c.Repo.Repository.EditWikiPage(c.User, f.OldTitle, f.Title, f.Content, f.Message); err != nil {
|
||||||
c.Handle(500, "EditWikiPage", err)
|
c.ServerError("EditWikiPage", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,7 +259,7 @@ func DeleteWikiPagePost(c *context.Context) {
|
|||||||
|
|
||||||
pageName := db.ToWikiPageName(pageURL)
|
pageName := db.ToWikiPageName(pageURL)
|
||||||
if err := c.Repo.Repository.DeleteWikiPage(c.User, pageName); err != nil {
|
if err := c.Repo.Repository.DeleteWikiPage(c.User, pageName); err != nil {
|
||||||
c.Handle(500, "DeleteWikiPage", err)
|
c.ServerError("DeleteWikiPage", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
package template
|
package template
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"container/list"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"mime"
|
"mime"
|
||||||
@@ -21,8 +20,11 @@ import (
|
|||||||
"golang.org/x/text/transform"
|
"golang.org/x/text/transform"
|
||||||
log "unknwon.dev/clog/v2"
|
log "unknwon.dev/clog/v2"
|
||||||
|
|
||||||
|
"github.com/gogs/git-module"
|
||||||
|
|
||||||
"gogs.io/gogs/internal/conf"
|
"gogs.io/gogs/internal/conf"
|
||||||
"gogs.io/gogs/internal/db"
|
"gogs.io/gogs/internal/db"
|
||||||
|
"gogs.io/gogs/internal/gitutil"
|
||||||
"gogs.io/gogs/internal/markup"
|
"gogs.io/gogs/internal/markup"
|
||||||
"gogs.io/gogs/internal/tool"
|
"gogs.io/gogs/internal/tool"
|
||||||
)
|
)
|
||||||
@@ -36,6 +38,9 @@ var (
|
|||||||
func FuncMap() []template.FuncMap {
|
func FuncMap() []template.FuncMap {
|
||||||
funcMapOnce.Do(func() {
|
funcMapOnce.Do(func() {
|
||||||
funcMap = []template.FuncMap{map[string]interface{}{
|
funcMap = []template.FuncMap{map[string]interface{}{
|
||||||
|
"BuildCommit": func() string {
|
||||||
|
return conf.BuildCommit
|
||||||
|
},
|
||||||
"Year": func() int {
|
"Year": func() int {
|
||||||
return time.Now().Year()
|
return time.Now().Year()
|
||||||
},
|
},
|
||||||
@@ -86,7 +91,6 @@ func FuncMap() []template.FuncMap {
|
|||||||
"DateFmtShort": func(t time.Time) string {
|
"DateFmtShort": func(t time.Time) string {
|
||||||
return t.Format("Jan 02, 2006")
|
return t.Format("Jan 02, 2006")
|
||||||
},
|
},
|
||||||
"List": List,
|
|
||||||
"SubStr": func(str string, start, length int) string {
|
"SubStr": func(str string, start, length int) string {
|
||||||
if len(str) == 0 {
|
if len(str) == 0 {
|
||||||
return ""
|
return ""
|
||||||
@@ -102,11 +106,10 @@ func FuncMap() []template.FuncMap {
|
|||||||
},
|
},
|
||||||
"Join": strings.Join,
|
"Join": strings.Join,
|
||||||
"EllipsisString": tool.EllipsisString,
|
"EllipsisString": tool.EllipsisString,
|
||||||
"DiffTypeToStr": DiffTypeToStr,
|
"DiffFileTypeToStr": DiffFileTypeToStr,
|
||||||
"DiffLineTypeToStr": DiffLineTypeToStr,
|
"DiffLineTypeToStr": DiffLineTypeToStr,
|
||||||
"Sha1": Sha1,
|
"Sha1": Sha1,
|
||||||
"ShortSHA1": tool.ShortSHA1,
|
"ShortSHA1": tool.ShortSHA1,
|
||||||
"MD5": tool.MD5,
|
|
||||||
"ActionContent2Commits": ActionContent2Commits,
|
"ActionContent2Commits": ActionContent2Commits,
|
||||||
"EscapePound": EscapePound,
|
"EscapePound": EscapePound,
|
||||||
"RenderCommitMessage": RenderCommitMessage,
|
"RenderCommitMessage": RenderCommitMessage,
|
||||||
@@ -126,6 +129,7 @@ func FuncMap() []template.FuncMap {
|
|||||||
}
|
}
|
||||||
return "tab-size-8"
|
return "tab-size-8"
|
||||||
},
|
},
|
||||||
|
"InferSubmoduleURL": gitutil.InferSubmoduleURL,
|
||||||
}}
|
}}
|
||||||
})
|
})
|
||||||
return funcMap
|
return funcMap
|
||||||
@@ -144,19 +148,6 @@ func NewLine2br(raw string) string {
|
|||||||
return strings.Replace(raw, "\n", "<br>", -1)
|
return strings.Replace(raw, "\n", "<br>", -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func List(l *list.List) chan interface{} {
|
|
||||||
e := l.Front()
|
|
||||||
c := make(chan interface{})
|
|
||||||
go func() {
|
|
||||||
for e != nil {
|
|
||||||
c <- e.Value
|
|
||||||
e = e.Next()
|
|
||||||
}
|
|
||||||
close(c)
|
|
||||||
}()
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
func Sha1(str string) string {
|
func Sha1(str string) string {
|
||||||
return tool.SHA1(str)
|
return tool.SHA1(str)
|
||||||
}
|
}
|
||||||
@@ -269,20 +260,22 @@ func EscapePound(str string) string {
|
|||||||
return strings.NewReplacer("%", "%25", "#", "%23", " ", "%20", "?", "%3F").Replace(str)
|
return strings.NewReplacer("%", "%25", "#", "%23", " ", "%20", "?", "%3F").Replace(str)
|
||||||
}
|
}
|
||||||
|
|
||||||
func DiffTypeToStr(diffType int) string {
|
func DiffFileTypeToStr(typ git.DiffFileType) string {
|
||||||
diffTypes := map[int]string{
|
return map[git.DiffFileType]string{
|
||||||
1: "add", 2: "modify", 3: "del", 4: "rename",
|
git.DiffFileAdd: "add",
|
||||||
}
|
git.DiffFileChange: "modify",
|
||||||
return diffTypes[diffType]
|
git.DiffFileDelete: "del",
|
||||||
|
git.DiffFileRename: "rename",
|
||||||
|
}[typ]
|
||||||
}
|
}
|
||||||
|
|
||||||
func DiffLineTypeToStr(diffType int) string {
|
func DiffLineTypeToStr(typ git.DiffLineType) string {
|
||||||
switch diffType {
|
switch typ {
|
||||||
case 2:
|
case git.DiffLineAdd:
|
||||||
return "add"
|
return "add"
|
||||||
case 3:
|
case git.DiffLineDelete:
|
||||||
return "del"
|
return "del"
|
||||||
case 4:
|
case git.DiffLineSection:
|
||||||
return "tag"
|
return "tag"
|
||||||
}
|
}
|
||||||
return "same"
|
return "same"
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
background-size: contain;
|
background-size: contain;
|
||||||
}
|
}
|
||||||
body:not(.full-width) {
|
body:not(.full-width) {
|
||||||
font-family: "PingFang SC", "Helvetica Neue", "Microsoft YaHei", Arial, Helvetica, sans-serif !important;
|
font-family: "Helvetica Neue", "Microsoft YaHei", Arial, Helvetica, sans-serif !important;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
@@ -23,14 +23,14 @@ h5,
|
|||||||
.ui.menu,
|
.ui.menu,
|
||||||
.ui.input input,
|
.ui.input input,
|
||||||
.ui.button:not(.label) {
|
.ui.button:not(.label) {
|
||||||
font-family: "PingFang SC", 'Hiragino Sans GB', "Helvetica Neue", "Microsoft YaHei", Arial, Helvetica, sans-serif !important;
|
font-family: "Helvetica Neue", "Microsoft YaHei", Arial, Helvetica, sans-serif !important;
|
||||||
}
|
}
|
||||||
img {
|
img {
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
pre,
|
pre,
|
||||||
code {
|
code {
|
||||||
font: 12px Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
font-family: Consolas, Liberation Mono, Menlo, monospace;
|
||||||
}
|
}
|
||||||
pre.raw,
|
pre.raw,
|
||||||
code.raw {
|
code.raw {
|
||||||
@@ -75,7 +75,7 @@ code.wrap {
|
|||||||
}
|
}
|
||||||
.following.bar.light {
|
.following.bar.light {
|
||||||
background-color: white;
|
background-color: white;
|
||||||
border-bottom: 1px solid #DDDDDD;
|
border-bottom: 1px solid #dddddd;
|
||||||
box-shadow: 0 2px 3px rgba(0, 0, 0, 0.04);
|
box-shadow: 0 2px 3px rgba(0, 0, 0, 0.04);
|
||||||
}
|
}
|
||||||
.following.bar .column .menu {
|
.following.bar .column .menu {
|
||||||
@@ -156,7 +156,7 @@ code.wrap {
|
|||||||
color: #d95c5c !important;
|
color: #d95c5c !important;
|
||||||
}
|
}
|
||||||
.ui .text.red a:hover {
|
.ui .text.red a:hover {
|
||||||
color: #E67777 !important;
|
color: #e67777 !important;
|
||||||
}
|
}
|
||||||
.ui .text.blue {
|
.ui .text.blue {
|
||||||
color: #428bca !important;
|
color: #428bca !important;
|
||||||
@@ -192,7 +192,7 @@ code.wrap {
|
|||||||
color: #6e5494 !important;
|
color: #6e5494 !important;
|
||||||
}
|
}
|
||||||
.ui .text.yellow {
|
.ui .text.yellow {
|
||||||
color: #FBBD08 !important;
|
color: #fbbd08 !important;
|
||||||
}
|
}
|
||||||
.ui .text.gold {
|
.ui .text.gold {
|
||||||
color: #a1882b !important;
|
color: #a1882b !important;
|
||||||
@@ -235,11 +235,11 @@ code.wrap {
|
|||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
.ui .warning.header {
|
.ui .warning.header {
|
||||||
background-color: #F9EDBE !important;
|
background-color: #f9edbe !important;
|
||||||
border-color: #F0C36D;
|
border-color: #f0c36d;
|
||||||
}
|
}
|
||||||
.ui .warning.segment {
|
.ui .warning.segment {
|
||||||
border-color: #F0C36D;
|
border-color: #f0c36d;
|
||||||
}
|
}
|
||||||
.ui .info.segment {
|
.ui .info.segment {
|
||||||
border: 1px solid #c5d5dd;
|
border: 1px solid #c5d5dd;
|
||||||
@@ -270,7 +270,7 @@ code.wrap {
|
|||||||
margin-left: 25px;
|
margin-left: 25px;
|
||||||
}
|
}
|
||||||
.ui .sha.label {
|
.ui .sha.label {
|
||||||
font-family: Consolas, Menlo, Monaco, "Lucida Console", monospace;
|
font-family: Consolas, Liberation Mono, Menlo, monospace;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
padding: 6px 10px 4px 10px;
|
padding: 6px 10px 4px 10px;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
@@ -1204,7 +1204,7 @@ footer .ui.language .menu {
|
|||||||
color: #000;
|
color: #000;
|
||||||
}
|
}
|
||||||
.repository .header-wrapper {
|
.repository .header-wrapper {
|
||||||
background-color: #FAFAFA;
|
background-color: #fafafa;
|
||||||
margin-top: -15px;
|
margin-top: -15px;
|
||||||
padding-top: 15px;
|
padding-top: 15px;
|
||||||
}
|
}
|
||||||
@@ -1279,7 +1279,7 @@ footer .ui.language .menu {
|
|||||||
line-height: 31px;
|
line-height: 31px;
|
||||||
}
|
}
|
||||||
.repository.branches:not(.settings) .ui.list > .item:not(:last-child) {
|
.repository.branches:not(.settings) .ui.list > .item:not(:last-child) {
|
||||||
border-bottom: 1px solid #DDD;
|
border-bottom: 1px solid #ddd;
|
||||||
}
|
}
|
||||||
.repository.branches:not(.settings) .ui.list > .item .column {
|
.repository.branches:not(.settings) .ui.list > .item .column {
|
||||||
padding: 5px 15px;
|
padding: 5px 15px;
|
||||||
@@ -1355,7 +1355,7 @@ footer .ui.language .menu {
|
|||||||
padding-bottom: 8px;
|
padding-bottom: 8px;
|
||||||
}
|
}
|
||||||
.repository.file.list #repo-files-table tr:hover {
|
.repository.file.list #repo-files-table tr:hover {
|
||||||
background-color: #ffffEE;
|
background-color: #ffffee;
|
||||||
}
|
}
|
||||||
.repository.file.list #file-content .header .octicon {
|
.repository.file.list #file-content .header .octicon {
|
||||||
padding-right: 5px;
|
padding-right: 5px;
|
||||||
@@ -1414,7 +1414,7 @@ footer .ui.language .menu {
|
|||||||
padding: 0.1em 0.5em;
|
padding: 0.1em 0.5em;
|
||||||
}
|
}
|
||||||
.repository.file.list #file-content #ipython-notebook .nb-stderr {
|
.repository.file.list #file-content #ipython-notebook .nb-stderr {
|
||||||
background-color: #FAA;
|
background-color: #faa;
|
||||||
}
|
}
|
||||||
.repository.file.list #file-content #ipython-notebook .nb-cell + .nb-cell {
|
.repository.file.list #file-content #ipython-notebook .nb-cell + .nb-cell {
|
||||||
margin-top: 0.5em;
|
margin-top: 0.5em;
|
||||||
@@ -1431,7 +1431,7 @@ footer .ui.language .menu {
|
|||||||
.repository.file.list #file-content #ipython-notebook .nb-raw-cell {
|
.repository.file.list #file-content #ipython-notebook .nb-raw-cell {
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
background-color: #f5f2f0;
|
background-color: #f5f2f0;
|
||||||
font-family: Consolas, Monaco, 'Andale Mono', monospace;
|
font-family: Consolas, Liberation Mono, Menlo, monospace;
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
margin: 0.5em 0;
|
margin: 0.5em 0;
|
||||||
}
|
}
|
||||||
@@ -1497,7 +1497,7 @@ footer .ui.language .menu {
|
|||||||
}
|
}
|
||||||
.repository.file.list #file-content .code-view * {
|
.repository.file.list #file-content .code-view * {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
font-family: Consolas, Liberation Mono, Menlo, monospace;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
}
|
}
|
||||||
.repository.file.list #file-content .code-view table {
|
.repository.file.list #file-content .code-view table {
|
||||||
@@ -1542,6 +1542,7 @@ footer .ui.language .menu {
|
|||||||
.repository.file.list #file-content .code-view .lines-code .hljs li {
|
.repository.file.list #file-content .code-view .lines-code .hljs li {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
padding-left: 5px;
|
||||||
}
|
}
|
||||||
.repository.file.list #file-content .code-view .lines-num pre li.active,
|
.repository.file.list #file-content .code-view .lines-num pre li.active,
|
||||||
.repository.file.list #file-content .code-view .lines-code pre li.active,
|
.repository.file.list #file-content .code-view .lines-code pre li.active,
|
||||||
@@ -1551,14 +1552,6 @@ footer .ui.language .menu {
|
|||||||
.repository.file.list #file-content .code-view .lines-code .hljs li.active {
|
.repository.file.list #file-content .code-view .lines-code .hljs li.active {
|
||||||
background: #ffffdd;
|
background: #ffffdd;
|
||||||
}
|
}
|
||||||
.repository.file.list #file-content .code-view .lines-num pre li:before,
|
|
||||||
.repository.file.list #file-content .code-view .lines-code pre li:before,
|
|
||||||
.repository.file.list #file-content .code-view .lines-num ol li:before,
|
|
||||||
.repository.file.list #file-content .code-view .lines-code ol li:before,
|
|
||||||
.repository.file.list #file-content .code-view .lines-num .hljs li:before,
|
|
||||||
.repository.file.list #file-content .code-view .lines-code .hljs li:before {
|
|
||||||
content: ' ';
|
|
||||||
}
|
|
||||||
.repository.file.list .sidebar {
|
.repository.file.list .sidebar {
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
}
|
}
|
||||||
@@ -1606,7 +1599,7 @@ footer .ui.language .menu {
|
|||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
.repository.file.editor .commit-form-wrapper .commit-form:before {
|
.repository.file.editor .commit-form-wrapper .commit-form:before {
|
||||||
border-right-color: #D4D4D5;
|
border-right-color: #d4d4d5;
|
||||||
border-width: 9px;
|
border-width: 9px;
|
||||||
margin-top: -9px;
|
margin-top: -9px;
|
||||||
}
|
}
|
||||||
@@ -1621,7 +1614,7 @@ footer .ui.language .menu {
|
|||||||
.repository.file.editor .commit-form-wrapper .commit-form .quick-pull-choice .branch-name {
|
.repository.file.editor .commit-form-wrapper .commit-form .quick-pull-choice .branch-name {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 3px 6px;
|
padding: 3px 6px;
|
||||||
font: 12px Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
font: 12px Consolas, Liberation Mono, Menlo, monospace;
|
||||||
color: rgba(0, 0, 0, 0.65);
|
color: rgba(0, 0, 0, 0.65);
|
||||||
background-color: rgba(209, 227, 237, 0.45);
|
background-color: rgba(209, 227, 237, 0.45);
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
@@ -1668,7 +1661,7 @@ footer .ui.language .menu {
|
|||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
.repository.new.issue .comment.form .content:before {
|
.repository.new.issue .comment.form .content:before {
|
||||||
border-right-color: #D4D4D5;
|
border-right-color: #d4d4d5;
|
||||||
border-width: 9px;
|
border-width: 9px;
|
||||||
margin-top: -9px;
|
margin-top: -9px;
|
||||||
}
|
}
|
||||||
@@ -1720,7 +1713,7 @@ footer .ui.language .menu {
|
|||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
.repository.view.issue .pull-desc code {
|
.repository.view.issue .pull-desc code {
|
||||||
color: #0166E6;
|
color: #0166e6;
|
||||||
}
|
}
|
||||||
.repository.view.issue .pull.tabular.menu {
|
.repository.view.issue .pull.tabular.menu {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
@@ -1801,7 +1794,7 @@ footer .ui.language .menu {
|
|||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
.repository.view.issue .comment-list .comment .content .header:before {
|
.repository.view.issue .comment-list .comment .content .header:before {
|
||||||
border-right-color: #D4D4D5;
|
border-right-color: #d4d4d5;
|
||||||
border-width: 9px;
|
border-width: 9px;
|
||||||
margin-top: -9px;
|
margin-top: -9px;
|
||||||
}
|
}
|
||||||
@@ -1827,7 +1820,7 @@ footer .ui.language .menu {
|
|||||||
}
|
}
|
||||||
.repository.view.issue .comment-list .comment .content > .bottom.segment .ui.images::after {
|
.repository.view.issue .comment-list .comment .content > .bottom.segment .ui.images::after {
|
||||||
clear: both;
|
clear: both;
|
||||||
content: ' ';
|
content: " ";
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
.repository.view.issue .comment-list .comment .content > .bottom.segment a {
|
.repository.view.issue .comment-list .comment .content > .bottom.segment a {
|
||||||
@@ -1842,7 +1835,7 @@ footer .ui.language .menu {
|
|||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
}
|
}
|
||||||
.repository.view.issue .comment-list .comment .content > .bottom.segment a:before {
|
.repository.view.issue .comment-list .comment .content > .bottom.segment a:before {
|
||||||
content: ' ';
|
content: " ";
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
@@ -1870,7 +1863,7 @@ footer .ui.language .menu {
|
|||||||
}
|
}
|
||||||
.repository.view.issue .comment-list .comment .ui.form textarea {
|
.repository.view.issue .comment-list .comment .ui.form textarea {
|
||||||
height: 200px;
|
height: 200px;
|
||||||
font-family: "Consolas", monospace;
|
font-family: Consolas, Liberation Mono, Menlo, monospace;
|
||||||
}
|
}
|
||||||
.repository.view.issue .comment-list .comment .edit.buttons {
|
.repository.view.issue .comment-list .comment .edit.buttons {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
@@ -1937,7 +1930,7 @@ footer .ui.language .menu {
|
|||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
.repository .comment.form .content .form:before {
|
.repository .comment.form .content .form:before {
|
||||||
border-right-color: #D4D4D5;
|
border-right-color: #d4d4d5;
|
||||||
border-width: 9px;
|
border-width: 9px;
|
||||||
margin-top: -9px;
|
margin-top: -9px;
|
||||||
}
|
}
|
||||||
@@ -1956,7 +1949,7 @@ footer .ui.language .menu {
|
|||||||
}
|
}
|
||||||
.repository .comment.form .content textarea {
|
.repository .comment.form .content textarea {
|
||||||
height: 200px;
|
height: 200px;
|
||||||
font-family: "Consolas", monospace;
|
font-family: Consolas, Liberation Mono, Menlo, monospace;
|
||||||
}
|
}
|
||||||
.repository .label.list {
|
.repository .label.list {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
@@ -1965,7 +1958,7 @@ footer .ui.language .menu {
|
|||||||
.repository .label.list > .item {
|
.repository .label.list > .item {
|
||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
border-bottom: 1px dashed #AAA;
|
border-bottom: 1px dashed #aaa;
|
||||||
}
|
}
|
||||||
.repository .label.list > .item a {
|
.repository .label.list > .item a {
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
@@ -1989,7 +1982,7 @@ footer .ui.language .menu {
|
|||||||
.repository .milestone.list > .item {
|
.repository .milestone.list > .item {
|
||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
border-bottom: 1px dashed #AAA;
|
border-bottom: 1px dashed #aaa;
|
||||||
}
|
}
|
||||||
.repository .milestone.list > .item > a {
|
.repository .milestone.list > .item > a {
|
||||||
padding-top: 5px;
|
padding-top: 5px;
|
||||||
@@ -2054,7 +2047,7 @@ footer .ui.language .menu {
|
|||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
.repository.compare.pull .comment.form .content:before {
|
.repository.compare.pull .comment.form .content:before {
|
||||||
border-right-color: #D4D4D5;
|
border-right-color: #d4d4d5;
|
||||||
border-width: 9px;
|
border-width: 9px;
|
||||||
margin-top: -9px;
|
margin-top: -9px;
|
||||||
}
|
}
|
||||||
@@ -2100,7 +2093,7 @@ footer .ui.language .menu {
|
|||||||
list-style: none;
|
list-style: none;
|
||||||
padding-bottom: 4px;
|
padding-bottom: 4px;
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
border-bottom: 1px dashed #DDD;
|
border-bottom: 1px dashed #ddd;
|
||||||
padding-left: 6px;
|
padding-left: 6px;
|
||||||
}
|
}
|
||||||
.repository .diff-detail-box span.status {
|
.repository .diff-detail-box span.status {
|
||||||
@@ -2146,7 +2139,7 @@ footer .ui.language .menu {
|
|||||||
}
|
}
|
||||||
.repository .diff-file-box .file-body.file-code .lines-num {
|
.repository .diff-file-box .file-body.file-code .lines-num {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
color: #A7A7A7;
|
color: #a7a7a7;
|
||||||
background: #fafafa;
|
background: #fafafa;
|
||||||
width: 1%;
|
width: 1%;
|
||||||
}
|
}
|
||||||
@@ -2155,7 +2148,7 @@ footer .ui.language .menu {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
.repository .diff-file-box .file-body.file-code .lines-num-old {
|
.repository .diff-file-box .file-body.file-code .lines-num-old {
|
||||||
border-right: 1px solid #DDD;
|
border-right: 1px solid #ddd;
|
||||||
}
|
}
|
||||||
.repository .diff-file-box .code-diff {
|
.repository .diff-file-box .code-diff {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
@@ -2175,6 +2168,7 @@ footer .ui.language .menu {
|
|||||||
}
|
}
|
||||||
.repository .diff-file-box .code-diff .lines-num::before {
|
.repository .diff-file-box .code-diff .lines-num::before {
|
||||||
content: attr(data-line-number);
|
content: attr(data-line-number);
|
||||||
|
font: Consolas, Liberation Mono, Menlo, monospace;
|
||||||
}
|
}
|
||||||
.repository .diff-file-box .code-diff .lines-num.lines-num-old,
|
.repository .diff-file-box .code-diff .lines-num.lines-num-old,
|
||||||
.repository .diff-file-box .code-diff .lines-num.lines-num-new {
|
.repository .diff-file-box .code-diff .lines-num.lines-num-new {
|
||||||
@@ -2185,8 +2179,8 @@ footer .ui.language .menu {
|
|||||||
color: #383636;
|
color: #383636;
|
||||||
}
|
}
|
||||||
.repository .diff-file-box .code-diff tbody tr.tag-code td {
|
.repository .diff-file-box .code-diff tbody tr.tag-code td {
|
||||||
background-color: #F0F0F0 !important;
|
background-color: #f0f0f0 !important;
|
||||||
border-color: #D2CECE !important;
|
border-color: #d2cece !important;
|
||||||
padding-top: 4px;
|
padding-top: 4px;
|
||||||
padding-bottom: 4px;
|
padding-bottom: 4px;
|
||||||
}
|
}
|
||||||
@@ -2261,7 +2255,7 @@ footer .ui.language .menu {
|
|||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
}
|
}
|
||||||
.repository.release #release-list {
|
.repository.release #release-list {
|
||||||
border-top: 1px solid #DDD;
|
border-top: 1px solid #ddd;
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
padding-top: 15px;
|
padding-top: 15px;
|
||||||
}
|
}
|
||||||
@@ -2286,7 +2280,7 @@ footer .ui.language .menu {
|
|||||||
margin-top: 6px;
|
margin-top: 6px;
|
||||||
}
|
}
|
||||||
.repository.release #release-list > li .detail {
|
.repository.release #release-list > li .detail {
|
||||||
border-left: 1px solid #DDD;
|
border-left: 1px solid #ddd;
|
||||||
}
|
}
|
||||||
.repository.release #release-list > li .detail .author img {
|
.repository.release #release-list > li .detail .author img {
|
||||||
margin-bottom: -3px;
|
margin-bottom: -3px;
|
||||||
@@ -2319,7 +2313,7 @@ footer .ui.language .menu {
|
|||||||
left: -5px;
|
left: -5px;
|
||||||
top: 40px;
|
top: 40px;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
border: 1px solid #FFF;
|
border: 1px solid #fff;
|
||||||
}
|
}
|
||||||
.repository.new.release .target {
|
.repository.new.release .target {
|
||||||
min-width: 500px;
|
min-width: 500px;
|
||||||
@@ -2348,7 +2342,7 @@ footer .ui.language .menu {
|
|||||||
.repository.forks .list .item {
|
.repository.forks .list .item {
|
||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
border-bottom: 1px solid #DDD;
|
border-bottom: 1px solid #ddd;
|
||||||
}
|
}
|
||||||
.repository.forks .list .item .ui.avatar {
|
.repository.forks .list .item .ui.avatar {
|
||||||
float: left;
|
float: left;
|
||||||
@@ -2365,7 +2359,7 @@ footer .ui.language .menu {
|
|||||||
font-size: 48px;
|
font-size: 48px;
|
||||||
}
|
}
|
||||||
.repository.wiki.new .CodeMirror .CodeMirror-code {
|
.repository.wiki.new .CodeMirror .CodeMirror-code {
|
||||||
font-family: "Consolas", monospace;
|
font-family: Consolas, Liberation Mono, Menlo, monospace;
|
||||||
}
|
}
|
||||||
.repository.wiki.new .CodeMirror .CodeMirror-code .cm-comment {
|
.repository.wiki.new .CodeMirror .CodeMirror-code .cm-comment {
|
||||||
background: inherit;
|
background: inherit;
|
||||||
@@ -2399,7 +2393,7 @@ footer .ui.language .menu {
|
|||||||
line-height: 2em;
|
line-height: 2em;
|
||||||
}
|
}
|
||||||
.repository.settings.collaboration .collaborator.list > .item:not(:last-child) {
|
.repository.settings.collaboration .collaborator.list > .item:not(:last-child) {
|
||||||
border-bottom: 1px solid #DDD;
|
border-bottom: 1px solid #ddd;
|
||||||
}
|
}
|
||||||
.repository.settings.collaboration #repo-collab-form #search-user-box .results {
|
.repository.settings.collaboration #repo-collab-form #search-user-box .results {
|
||||||
left: 7px;
|
left: 7px;
|
||||||
@@ -2491,7 +2485,7 @@ footer .ui.language .menu {
|
|||||||
#search-repo-box .results .item,
|
#search-repo-box .results .item,
|
||||||
#search-user-box .results .item {
|
#search-user-box .results .item {
|
||||||
padding: 10px 15px;
|
padding: 10px 15px;
|
||||||
border-bottom: 1px solid #DDD;
|
border-bottom: 1px solid #ddd;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
#search-repo-box .results .item:hover,
|
#search-repo-box .results .item:hover,
|
||||||
@@ -2510,7 +2504,7 @@ footer .ui.language .menu {
|
|||||||
.issue.list > .item {
|
.issue.list > .item {
|
||||||
padding-top: 15px;
|
padding-top: 15px;
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
border-bottom: 1px dashed #AAA;
|
border-bottom: 1px dashed #aaa;
|
||||||
}
|
}
|
||||||
.issue.list > .item .title {
|
.issue.list > .item .title {
|
||||||
color: #444;
|
color: #444;
|
||||||
@@ -2546,7 +2540,7 @@ footer .ui.language .menu {
|
|||||||
.ui.form .dropzone {
|
.ui.form .dropzone {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
border: 2px dashed #0087F7;
|
border: 2px dashed #0087f7;
|
||||||
box-shadow: none !important;
|
box-shadow: none !important;
|
||||||
}
|
}
|
||||||
.ui.form .dropzone .dz-error-message {
|
.ui.form .dropzone .dz-error-message {
|
||||||
@@ -2688,7 +2682,7 @@ footer .ui.language .menu {
|
|||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
#avatar-arrow:before {
|
#avatar-arrow:before {
|
||||||
border-right-color: #D4D4D5;
|
border-right-color: #d4d4d5;
|
||||||
border-width: 9px;
|
border-width: 9px;
|
||||||
margin-top: -9px;
|
margin-top: -9px;
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,7 +1,7 @@
|
|||||||
@footer-margin: 40px;
|
@footer-margin: 40px;
|
||||||
|
|
||||||
body:not(.full-width) {
|
body:not(.full-width) {
|
||||||
font-family: "PingFang SC", "Helvetica Neue", "Microsoft YaHei", Arial, Helvetica, sans-serif !important;
|
font-family: "Helvetica Neue", "Microsoft YaHei", Arial, Helvetica, sans-serif !important;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
@@ -10,18 +10,23 @@ body:not(.full-width) {
|
|||||||
.ui.container:not(.fluid) {
|
.ui.container:not(.fluid) {
|
||||||
width: 980px !important;
|
width: 980px !important;
|
||||||
}
|
}
|
||||||
h1, h2, h3, h4, h5,
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
.ui.header,
|
.ui.header,
|
||||||
.ui.menu,
|
.ui.menu,
|
||||||
.ui.input input,
|
.ui.input input,
|
||||||
.ui.button:not(.label) {
|
.ui.button:not(.label) {
|
||||||
font-family: "PingFang SC", 'Hiragino Sans GB', "Helvetica Neue", "Microsoft YaHei", Arial, Helvetica, sans-serif !important;
|
font-family: "Helvetica Neue", "Microsoft YaHei", Arial, Helvetica, sans-serif !important;
|
||||||
}
|
}
|
||||||
img {
|
img {
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
pre, code {
|
pre,
|
||||||
font: 12px Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
code {
|
||||||
|
font-family: Consolas, Liberation Mono, Menlo, monospace;
|
||||||
&.raw {
|
&.raw {
|
||||||
padding: 7px 12px;
|
padding: 7px 12px;
|
||||||
margin: 10px 0;
|
margin: 10px 0;
|
||||||
@@ -65,7 +70,7 @@ pre, code {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
&.light {
|
&.light {
|
||||||
background-color: white;
|
background-color: white;
|
||||||
border-bottom: 1px solid #DDDDDD;
|
border-bottom: 1px solid #dddddd;
|
||||||
box-shadow: 0 2px 3px rgba(0, 0, 0, 0.04);
|
box-shadow: 0 2px 3px rgba(0, 0, 0, 0.04);
|
||||||
}
|
}
|
||||||
.column .menu {
|
.column .menu {
|
||||||
@@ -84,7 +89,7 @@ pre, code {
|
|||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
.top.menu a.item:hover {
|
.top.menu a.item:hover {
|
||||||
color: rgba(0,0,0,.45);
|
color: rgba(0, 0, 0, 0.45);
|
||||||
}
|
}
|
||||||
.top.menu .menu {
|
.top.menu .menu {
|
||||||
z-index: 900;
|
z-index: 900;
|
||||||
@@ -160,7 +165,7 @@ pre, code {
|
|||||||
a {
|
a {
|
||||||
color: #d95c5c !important;
|
color: #d95c5c !important;
|
||||||
&:hover {
|
&:hover {
|
||||||
color: #E67777 !important;
|
color: #e67777 !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -198,7 +203,7 @@ pre, code {
|
|||||||
color: #6e5494 !important;
|
color: #6e5494 !important;
|
||||||
}
|
}
|
||||||
&.yellow {
|
&.yellow {
|
||||||
color: #FBBD08 !important;
|
color: #fbbd08 !important;
|
||||||
}
|
}
|
||||||
&.gold {
|
&.gold {
|
||||||
color: #a1882b !important;
|
color: #a1882b !important;
|
||||||
@@ -249,11 +254,11 @@ pre, code {
|
|||||||
}
|
}
|
||||||
.warning {
|
.warning {
|
||||||
&.header {
|
&.header {
|
||||||
background-color: #F9EDBE !important;
|
background-color: #f9edbe !important;
|
||||||
border-color: #F0C36D;
|
border-color: #f0c36d;
|
||||||
}
|
}
|
||||||
&.segment {
|
&.segment {
|
||||||
border-color: #F0C36D;
|
border-color: #f0c36d;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.info {
|
.info {
|
||||||
@@ -261,7 +266,8 @@ pre, code {
|
|||||||
border: 1px solid #c5d5dd;
|
border: 1px solid #c5d5dd;
|
||||||
&.top {
|
&.top {
|
||||||
background-color: #e6f1f6 !important;
|
background-color: #e6f1f6 !important;
|
||||||
h3, h4 {
|
h3,
|
||||||
|
h4 {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
h3:last-child {
|
h3:last-child {
|
||||||
@@ -293,7 +299,7 @@ pre, code {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.sha.label {
|
.sha.label {
|
||||||
font-family: Consolas, Menlo, Monaco, "Lucida Console", monospace;
|
font-family: Consolas, Liberation Mono, Menlo, monospace;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
padding: 6px 10px 4px 10px;
|
padding: 6px 10px 4px 10px;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
@@ -324,8 +330,8 @@ pre, code {
|
|||||||
height: auto;
|
height: auto;
|
||||||
border-top: none;
|
border-top: none;
|
||||||
line-height: 1em;
|
line-height: 1em;
|
||||||
color: rgba(0,0,0,.8);
|
color: rgba(0, 0, 0, 0.8);
|
||||||
padding: .71428571em 1.14285714em !important;
|
padding: 0.71428571em 1.14285714em !important;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
text-transform: none;
|
text-transform: none;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
@@ -335,8 +341,8 @@ pre, code {
|
|||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
&:hover {
|
&:hover {
|
||||||
background: rgba(0,0,0,.05);
|
background: rgba(0, 0, 0, 0.05);
|
||||||
color: rgba(0,0,0,.8);
|
color: rgba(0, 0, 0, 0.8);
|
||||||
z-index: 13;
|
z-index: 13;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,7 +76,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.header-wrapper {
|
.header-wrapper {
|
||||||
background-color: #FAFAFA;
|
background-color: #fafafa;
|
||||||
margin-top: -15px;
|
margin-top: -15px;
|
||||||
padding-top: 15px;
|
padding-top: 15px;
|
||||||
|
|
||||||
@@ -141,7 +141,7 @@
|
|||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
padding: 0 5px;
|
padding: 0 5px;
|
||||||
&:first-child {
|
&:first-child {
|
||||||
border-radius: .28571429rem 0 0 .28571429rem;
|
border-radius: 0.28571429rem 0 0 0.28571429rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.icon.button {
|
.icon.button {
|
||||||
@@ -160,7 +160,7 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
line-height: 31px;
|
line-height: 31px;
|
||||||
&:not(:last-child) {
|
&:not(:last-child) {
|
||||||
border-bottom: 1px solid #DDD;
|
border-bottom: 1px solid #ddd;
|
||||||
}
|
}
|
||||||
.column {
|
.column {
|
||||||
padding: 5px 15px;
|
padding: 5px 15px;
|
||||||
@@ -240,7 +240,8 @@
|
|||||||
&.octicon-mail-reply {
|
&.octicon-mail-reply {
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
&.octicon-file-directory, &.octicon-file-submodule {
|
&.octicon-file-directory,
|
||||||
|
&.octicon-file-submodule {
|
||||||
color: #1e70bf;
|
color: #1e70bf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -250,7 +251,7 @@
|
|||||||
padding-bottom: 8px;
|
padding-bottom: 8px;
|
||||||
}
|
}
|
||||||
tr:hover {
|
tr:hover {
|
||||||
background-color: #ffffEE;
|
background-color: #ffffee;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -309,14 +310,15 @@
|
|||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nb-stdout, .nb-stderr {
|
.nb-stdout,
|
||||||
|
.nb-stderr {
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
margin: 1em 0;
|
margin: 1em 0;
|
||||||
padding: 0.1em 0.5em;
|
padding: 0.1em 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nb-stderr {
|
.nb-stderr {
|
||||||
background-color: #FAA;
|
background-color: #faa;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nb-cell + .nb-cell {
|
.nb-cell + .nb-cell {
|
||||||
@@ -338,9 +340,9 @@
|
|||||||
.nb-raw-cell {
|
.nb-raw-cell {
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
background-color: #f5f2f0;
|
background-color: #f5f2f0;
|
||||||
font-family: Consolas, Monaco, 'Andale Mono', monospace;
|
font-family: Consolas, Liberation Mono, Menlo, monospace;
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
margin: .5em 0;
|
margin: 0.5em 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nb-input:before,
|
.nb-input:before,
|
||||||
@@ -418,7 +420,7 @@
|
|||||||
.code-view {
|
.code-view {
|
||||||
* {
|
* {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
font-family: Consolas, Liberation Mono, Menlo, monospace;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -457,12 +459,10 @@
|
|||||||
li {
|
li {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
padding-left: 5px;
|
||||||
&.active {
|
&.active {
|
||||||
background: #ffffdd;
|
background: #ffffdd;
|
||||||
}
|
}
|
||||||
&:before {
|
|
||||||
content: ' ';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -520,7 +520,7 @@
|
|||||||
.branch-name {
|
.branch-name {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 3px 6px;
|
padding: 3px 6px;
|
||||||
font: 12px Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
font: 12px Consolas, Liberation Mono, Menlo, monospace;
|
||||||
color: rgba(0, 0, 0, 0.65);
|
color: rgba(0, 0, 0, 0.65);
|
||||||
background-color: rgba(209, 227, 237, 0.45);
|
background-color: rgba(209, 227, 237, 0.45);
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
@@ -584,7 +584,6 @@
|
|||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&.view.issue {
|
&.view.issue {
|
||||||
@@ -619,7 +618,7 @@
|
|||||||
}
|
}
|
||||||
.pull-desc {
|
.pull-desc {
|
||||||
code {
|
code {
|
||||||
color: #0166E6;
|
color: #0166e6;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.pull {
|
.pull {
|
||||||
@@ -713,7 +712,7 @@
|
|||||||
background: #f3f4f5;
|
background: #f3f4f5;
|
||||||
.ui.images::after {
|
.ui.images::after {
|
||||||
clear: both;
|
clear: both;
|
||||||
content: ' ';
|
content: " ";
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
a {
|
a {
|
||||||
@@ -727,7 +726,7 @@
|
|||||||
max-width: 150px;
|
max-width: 150px;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
&:before {
|
&:before {
|
||||||
content:' ';
|
content: " ";
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
@@ -760,7 +759,7 @@
|
|||||||
}
|
}
|
||||||
textarea {
|
textarea {
|
||||||
height: 200px;
|
height: 200px;
|
||||||
font-family: "Consolas", monospace;
|
font-family: Consolas, Liberation Mono, Menlo, monospace;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -840,7 +839,7 @@
|
|||||||
}
|
}
|
||||||
textarea {
|
textarea {
|
||||||
height: 200px;
|
height: 200px;
|
||||||
font-family: "Consolas", monospace;
|
font-family: Consolas, Liberation Mono, Menlo, monospace;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -851,7 +850,7 @@
|
|||||||
> .item {
|
> .item {
|
||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
border-bottom: 1px dashed #AAA;
|
border-bottom: 1px dashed #aaa;
|
||||||
a {
|
a {
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
padding-top: 5px;
|
padding-top: 5px;
|
||||||
@@ -876,7 +875,7 @@
|
|||||||
> .item {
|
> .item {
|
||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
border-bottom: 1px dashed #AAA;
|
border-bottom: 1px dashed #aaa;
|
||||||
> a {
|
> a {
|
||||||
padding-top: 5px;
|
padding-top: 5px;
|
||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
@@ -979,7 +978,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
&.ui.basic.striped.table tbody tr:nth-child(2n) {
|
&.ui.basic.striped.table tbody tr:nth-child(2n) {
|
||||||
background-color: rgba(0, 0, 0, .02)!important;
|
background-color: rgba(0, 0, 0, 0.02) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -995,7 +994,7 @@
|
|||||||
list-style: none;
|
list-style: none;
|
||||||
padding-bottom: 4px;
|
padding-bottom: 4px;
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
border-bottom: 1px dashed #DDD;
|
border-bottom: 1px dashed #ddd;
|
||||||
padding-left: 6px;
|
padding-left: 6px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1048,7 +1047,7 @@
|
|||||||
.file-body.file-code {
|
.file-body.file-code {
|
||||||
.lines-num {
|
.lines-num {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
color: #A7A7A7;
|
color: #a7a7a7;
|
||||||
background: #fafafa;
|
background: #fafafa;
|
||||||
width: 1%;
|
width: 1%;
|
||||||
|
|
||||||
@@ -1058,7 +1057,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.lines-num-old {
|
.lines-num-old {
|
||||||
border-right: 1px solid #DDD;
|
border-right: 1px solid #ddd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.code-diff {
|
.code-diff {
|
||||||
@@ -1079,9 +1078,11 @@
|
|||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
content: attr(data-line-number);
|
content: attr(data-line-number);
|
||||||
|
font: Consolas, Liberation Mono, Menlo, monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.lines-num-old, &.lines-num-new {
|
&.lines-num-old,
|
||||||
|
&.lines-num-new {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
&:hover {
|
&:hover {
|
||||||
color: #383636;
|
color: #383636;
|
||||||
@@ -1090,11 +1091,10 @@
|
|||||||
}
|
}
|
||||||
tbody {
|
tbody {
|
||||||
tr {
|
tr {
|
||||||
|
|
||||||
&.tag-code {
|
&.tag-code {
|
||||||
td {
|
td {
|
||||||
background-color: #F0F0F0 !important;
|
background-color: #f0f0f0 !important;
|
||||||
border-color: #D2CECE!important;
|
border-color: #d2cece !important;
|
||||||
padding-top: 4px;
|
padding-top: 4px;
|
||||||
padding-bottom: 4px;
|
padding-bottom: 4px;
|
||||||
}
|
}
|
||||||
@@ -1115,7 +1115,6 @@
|
|||||||
pre {
|
pre {
|
||||||
background-color: #eaffea !important;
|
background-color: #eaffea !important;
|
||||||
border-color: #c1e9c1 !important;
|
border-color: #c1e9c1 !important;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
td {
|
td {
|
||||||
@@ -1179,7 +1178,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.clone.button:first-child {
|
.clone.button:first-child {
|
||||||
border-radius: .28571429rem 0 0 .28571429rem;
|
border-radius: 0.28571429rem 0 0 0.28571429rem;
|
||||||
}
|
}
|
||||||
.ui.action.small.input {
|
.ui.action.small.input {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -1194,7 +1193,7 @@
|
|||||||
|
|
||||||
&.release {
|
&.release {
|
||||||
#release-list {
|
#release-list {
|
||||||
border-top: 1px solid #DDD;
|
border-top: 1px solid #ddd;
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
padding-top: 15px;
|
padding-top: 15px;
|
||||||
|
|
||||||
@@ -1220,7 +1219,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.detail {
|
.detail {
|
||||||
border-left: 1px solid #DDD;
|
border-left: 1px solid #ddd;
|
||||||
|
|
||||||
.author {
|
.author {
|
||||||
img {
|
img {
|
||||||
@@ -1260,7 +1259,7 @@
|
|||||||
left: -5px;
|
left: -5px;
|
||||||
top: 40px;
|
top: 40px;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
border: 1px solid #FFF;
|
border: 1px solid #fff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1299,7 +1298,7 @@
|
|||||||
.item {
|
.item {
|
||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
border-bottom: 1px solid #DDD;
|
border-bottom: 1px solid #ddd;
|
||||||
|
|
||||||
.ui.avatar {
|
.ui.avatar {
|
||||||
float: left;
|
float: left;
|
||||||
@@ -1327,7 +1326,7 @@
|
|||||||
&.new {
|
&.new {
|
||||||
.CodeMirror {
|
.CodeMirror {
|
||||||
.CodeMirror-code {
|
.CodeMirror-code {
|
||||||
font-family: "Consolas", monospace;
|
font-family: Consolas, Liberation Mono, Menlo, monospace;
|
||||||
.cm-comment {
|
.cm-comment {
|
||||||
background: inherit;
|
background: inherit;
|
||||||
}
|
}
|
||||||
@@ -1351,7 +1350,12 @@
|
|||||||
padding-left: 25px;
|
padding-left: 25px;
|
||||||
margin-left: -25px;
|
margin-left: -25px;
|
||||||
|
|
||||||
h1, h2, h3, h4, h5, h6 {
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6 {
|
||||||
&:first-of-type {
|
&:first-of-type {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
@@ -1370,7 +1374,7 @@
|
|||||||
line-height: 2em;
|
line-height: 2em;
|
||||||
|
|
||||||
&:not(:last-child) {
|
&:not(:last-child) {
|
||||||
border-bottom: 1px solid #DDD;
|
border-bottom: 1px solid #ddd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1505,12 +1509,12 @@
|
|||||||
|
|
||||||
.item {
|
.item {
|
||||||
padding: 10px 15px;
|
padding: 10px 15px;
|
||||||
border-bottom: 1px solid #DDD;
|
border-bottom: 1px solid #ddd;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: rgba(0,0,0,.05)!important;
|
background: rgba(0, 0, 0, 0.05) !important;
|
||||||
color: rgba(0,0,0,.95)!important;
|
color: rgba(0, 0, 0, 0.95) !important;
|
||||||
}
|
}
|
||||||
img {
|
img {
|
||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
@@ -1525,7 +1529,7 @@
|
|||||||
> .item {
|
> .item {
|
||||||
padding-top: 15px;
|
padding-top: 15px;
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
border-bottom: 1px dashed #AAA;
|
border-bottom: 1px dashed #aaa;
|
||||||
.title {
|
.title {
|
||||||
color: #444;
|
color: #444;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
@@ -1565,7 +1569,7 @@
|
|||||||
.dropzone {
|
.dropzone {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
border: 2px dashed #0087F7;
|
border: 2px dashed #0087f7;
|
||||||
box-shadow: none !important;
|
box-shadow: none !important;
|
||||||
.dz-error-message {
|
.dz-error-message {
|
||||||
top: 140px;
|
top: 140px;
|
||||||
@@ -1701,7 +1705,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
#avatar-arrow {
|
#avatar-arrow {
|
||||||
&:before, &:after {
|
&:before,
|
||||||
|
&:after {
|
||||||
right: 100%;
|
right: 100%;
|
||||||
top: 20px;
|
top: 20px;
|
||||||
border: solid transparent;
|
border: solid transparent;
|
||||||
@@ -1712,7 +1717,7 @@
|
|||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
&:before {
|
&:before {
|
||||||
border-right-color: #D4D4D5;
|
border-right-color: #d4d4d5;
|
||||||
border-width: 9px;
|
border-width: 9px;
|
||||||
margin-top: -9px;
|
margin-top: -9px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -458,11 +458,11 @@
|
|||||||
<dt>{{.i18n.Tr "admin.config.git.disable_diff_highlight"}}</dt>
|
<dt>{{.i18n.Tr "admin.config.git.disable_diff_highlight"}}</dt>
|
||||||
<dd><i class="fa fa{{if .Git.DisableDiffHighlight}}-check{{end}}-square-o"></i></dd>
|
<dd><i class="fa fa{{if .Git.DisableDiffHighlight}}-check{{end}}-square-o"></i></dd>
|
||||||
<dt>{{.i18n.Tr "admin.config.git.max_diff_lines"}}</dt>
|
<dt>{{.i18n.Tr "admin.config.git.max_diff_lines"}}</dt>
|
||||||
<dd>{{.Git.MaxGitDiffLines}}</dd>
|
<dd>{{.Git.MaxDiffLines}}</dd>
|
||||||
<dt>{{.i18n.Tr "admin.config.git.max_diff_line_characters"}}</dt>
|
<dt>{{.i18n.Tr "admin.config.git.max_diff_line_characters"}}</dt>
|
||||||
<dd>{{.Git.MaxGitDiffLineCharacters}}</dd>
|
<dd>{{.Git.MaxDiffLineChars}}</dd>
|
||||||
<dt>{{.i18n.Tr "admin.config.git.max_diff_files"}}</dt>
|
<dt>{{.i18n.Tr "admin.config.git.max_diff_files"}}</dt>
|
||||||
<dd>{{.Git.MaxGitDiffFiles}}</dd>
|
<dd>{{.Git.MaxDiffFiles}}</dd>
|
||||||
<dt>{{.i18n.Tr "admin.config.git.gc_args"}}</dt>
|
<dt>{{.i18n.Tr "admin.config.git.gc_args"}}</dt>
|
||||||
<dd><code>{{.Git.GCArgs}}</code></dd>
|
<dd><code>{{.Git.GCArgs}}</code></dd>
|
||||||
|
|
||||||
|
|||||||
@@ -60,7 +60,7 @@
|
|||||||
|
|
||||||
<!-- Stylesheet -->
|
<!-- Stylesheet -->
|
||||||
<link rel="stylesheet" href="{{AppSubURL}}/css/semantic-2.4.2.min.css">
|
<link rel="stylesheet" href="{{AppSubURL}}/css/semantic-2.4.2.min.css">
|
||||||
<link rel="stylesheet" href="{{AppSubURL}}/css/gogs.css?v={{MD5 AppVer}}">
|
<link rel="stylesheet" href="{{AppSubURL}}/css/gogs.css?v={{BuildCommit}}">
|
||||||
<noscript>
|
<noscript>
|
||||||
<style>
|
<style>
|
||||||
.dropdown:hover > .menu { display: block; }
|
.dropdown:hover > .menu { display: block; }
|
||||||
@@ -70,7 +70,7 @@
|
|||||||
|
|
||||||
<!-- JavaScript -->
|
<!-- JavaScript -->
|
||||||
<script src="{{AppSubURL}}/js/semantic-2.4.2.min.js"></script>
|
<script src="{{AppSubURL}}/js/semantic-2.4.2.min.js"></script>
|
||||||
<script src="{{AppSubURL}}/js/gogs.js?v={{MD5 AppVer}}"></script>
|
<script src="{{AppSubURL}}/js/gogs.js?v={{BuildCommit}}"></script>
|
||||||
|
|
||||||
<title>{{if .Title}}{{.Title}} - {{end}}{{AppName}}</title>
|
<title>{{if .Title}}{{.Title}} - {{end}}{{AppName}}</title>
|
||||||
|
|
||||||
|
|||||||
@@ -29,8 +29,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{{ $r:= List .Commits}}
|
{{range .Commits}}
|
||||||
{{range $r}}
|
|
||||||
<tr>
|
<tr>
|
||||||
<td class="author">
|
<td class="author">
|
||||||
{{if .User}}
|
{{if .User}}
|
||||||
@@ -47,7 +46,7 @@
|
|||||||
{{else}}
|
{{else}}
|
||||||
<a rel="nofollow" class="ui sha label" href="{{AppSubURL}}/{{$.Username}}/{{$.Reponame}}/commit/{{.ID}}">{{ShortSHA1 .ID.String}}</a>
|
<a rel="nofollow" class="ui sha label" href="{{AppSubURL}}/{{$.Username}}/{{$.Reponame}}/commit/{{.ID}}">{{ShortSHA1 .ID.String}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
<span class="{{if gt .ParentCount 1}}grey text {{end}} has-emoji">{{RenderCommitMessage false .Summary $.RepoLink $.Repository.ComposeMetas | Str2HTML}}</span>
|
<span class="{{if gt .ParentsCount 1}}grey text {{end}} has-emoji">{{RenderCommitMessage false .Summary $.RepoLink $.Repository.ComposeMetas | Str2HTML}}</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="grey text right aligned">{{TimeSince .Author.When $.Lang}}</td>
|
<td class="grey text right aligned">{{TimeSince .Author.When $.Lang}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<div class="diff-detail-box diff-box">
|
<div class="diff-detail-box diff-box">
|
||||||
<div>
|
<div>
|
||||||
<i class="fa fa-retweet"></i>
|
<i class="fa fa-retweet"></i>
|
||||||
{{.i18n.Tr "repo.diff.stats_desc" .Diff.NumFiles .Diff.TotalAddition .Diff.TotalDeletion | Str2HTML}}
|
{{.i18n.Tr "repo.diff.stats_desc" .Diff.NumFiles .Diff.TotalAdditions .Diff.TotalDeletions | Str2HTML}}
|
||||||
<div class="ui right">
|
<div class="ui right">
|
||||||
<a class="ui tiny basic toggle button" href="?style={{if .IsSplitStyle}}unified{{else}}split{{end}}">{{ if .IsSplitStyle }}{{.i18n.Tr "repo.diff.show_unified_view"}}{{else}}{{.i18n.Tr "repo.diff.show_split_view"}}{{end}}</a>
|
<a class="ui tiny basic toggle button" href="?style={{if .IsSplitStyle}}unified{{else}}split{{end}}">{{ if .IsSplitStyle }}{{.i18n.Tr "repo.diff.show_unified_view"}}{{else}}{{.i18n.Tr "repo.diff.show_split_view"}}{{end}}</a>
|
||||||
<a class="ui tiny basic toggle button" data-target="#diff-files">{{.i18n.Tr "repo.diff.show_diff_stats"}}</a>
|
<a class="ui tiny basic toggle button" data-target="#diff-files">{{.i18n.Tr "repo.diff.show_diff_stats"}}</a>
|
||||||
@@ -14,19 +14,19 @@
|
|||||||
{{range .Diff.Files}}
|
{{range .Diff.Files}}
|
||||||
<li>
|
<li>
|
||||||
<div class="diff-counter count pull-right">
|
<div class="diff-counter count pull-right">
|
||||||
{{if not .IsBin}}
|
{{if not .IsBinary}}
|
||||||
<span class="add" data-line="{{.Addition}}">{{.Addition}}</span>
|
<span class="add" data-line="{{.NumAdditions}}">{{.NumAdditions}}</span>
|
||||||
<span class="bar">
|
<span class="bar">
|
||||||
<span class="pull-left add"></span>
|
<span class="pull-left add"></span>
|
||||||
<span class="pull-left del"></span>
|
<span class="pull-left del"></span>
|
||||||
</span>
|
</span>
|
||||||
<span class="del" data-line="{{.Deletion}}">{{.Deletion}}</span>
|
<span class="del" data-line="{{.NumDeletions}}">{{.NumDeletions}}</span>
|
||||||
{{else}}
|
{{else}}
|
||||||
<span>{{$.i18n.Tr "repo.diff.bin"}}</span>
|
<span>{{$.i18n.Tr "repo.diff.bin"}}</span>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<!-- todo finish all file status, now modify, add, delete and rename -->
|
<!-- todo finish all file status, now modify, add, delete and rename -->
|
||||||
<span class="status {{DiffTypeToStr .GetType}} poping up" data-content="{{DiffTypeToStr .GetType}}" data-variation="inverted tiny" data-position="right center"> </span>
|
<span class="status {{DiffFileTypeToStr .Type}} poping up" data-content="{{DiffFileTypeToStr .Type}}" data-variation="inverted tiny" data-position="right center"> </span>
|
||||||
<a class="file" href="#diff-{{.Index}}">{{.Name}}</a>
|
<a class="file" href="#diff-{{.Index}}">{{.Name}}</a>
|
||||||
</li>
|
</li>
|
||||||
{{end}}
|
{{end}}
|
||||||
@@ -40,12 +40,12 @@
|
|||||||
{{$.i18n.Tr "repo.diff.file_suppressed"}}
|
{{$.i18n.Tr "repo.diff.file_suppressed"}}
|
||||||
<div class="diff-counter count ui left">
|
<div class="diff-counter count ui left">
|
||||||
{{if not $file.IsRenamed}}
|
{{if not $file.IsRenamed}}
|
||||||
<span class="add" data-line="{{.Addition}}">+ {{.Addition}}</span>
|
<span class="add" data-line="{{.NumAdditions}}">+ {{.NumAdditions}}</span>
|
||||||
<span class="bar">
|
<span class="bar">
|
||||||
<span class="pull-left add"></span>
|
<span class="pull-left add"></span>
|
||||||
<span class="pull-left del"></span>
|
<span class="pull-left del"></span>
|
||||||
</span>
|
</span>
|
||||||
<span class="del" data-line="{{.Deletion}}">- {{.Deletion}}</span>
|
<span class="del" data-line="{{.NumDeletions}}">- {{.NumDeletions}}</span>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<span class="file">{{$file.Name}}</span>
|
<span class="file">{{$file.Name}}</span>
|
||||||
@@ -55,15 +55,15 @@
|
|||||||
<div class="diff-file-box diff-box file-content {{TabSizeClass $.Editorconfig $file.Name}}" id="diff-{{.Index}}">
|
<div class="diff-file-box diff-box file-content {{TabSizeClass $.Editorconfig $file.Name}}" id="diff-{{.Index}}">
|
||||||
<h4 class="ui top attached normal header">
|
<h4 class="ui top attached normal header">
|
||||||
<div class="diff-counter count ui left">
|
<div class="diff-counter count ui left">
|
||||||
{{if $file.IsBin}}
|
{{if $file.IsBinary}}
|
||||||
{{$.i18n.Tr "repo.diff.bin"}}
|
{{$.i18n.Tr "repo.diff.bin"}}
|
||||||
{{else if not $file.IsRenamed}}
|
{{else if not $file.IsRenamed}}
|
||||||
<span class="add" data-line="{{.Addition}}">+ {{.Addition}}</span>
|
<span class="add" data-line="{{.NumAdditions}}">+ {{.NumAdditions}}</span>
|
||||||
<span class="bar">
|
<span class="bar">
|
||||||
<span class="pull-left add"></span>
|
<span class="pull-left add"></span>
|
||||||
<span class="pull-left del"></span>
|
<span class="pull-left del"></span>
|
||||||
</span>
|
</span>
|
||||||
<span class="del" data-line="{{.Deletion}}">- {{.Deletion}}</span>
|
<span class="del" data-line="{{.NumDeletions}}">- {{.NumDeletions}}</span>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<span class="file">{{if $file.IsRenamed}}{{$file.OldName}} → {{end}}{{$file.Name}}</span>
|
<span class="file">{{if $file.IsRenamed}}{{$file.OldName}} → {{end}}{{$file.Name}}</span>
|
||||||
@@ -80,7 +80,7 @@
|
|||||||
<div class="ui unstackable attached table segment">
|
<div class="ui unstackable attached table segment">
|
||||||
{{if not $file.IsRenamed}}
|
{{if not $file.IsRenamed}}
|
||||||
{{$isImage := (call $.IsImageFile $file.Name)}}
|
{{$isImage := (call $.IsImageFile $file.Name)}}
|
||||||
{{if and $isImage}}
|
{{if $isImage}}
|
||||||
<div class="center">
|
<div class="center">
|
||||||
<img src="{{$.RawPath}}/{{EscapePound .Name}}">
|
<img src="{{$.RawPath}}/{{EscapePound .Name}}">
|
||||||
</div>
|
</div>
|
||||||
@@ -92,22 +92,22 @@
|
|||||||
{{$highlightClass := $file.HighlightClass}}
|
{{$highlightClass := $file.HighlightClass}}
|
||||||
{{range $j, $section := $file.Sections}}
|
{{range $j, $section := $file.Sections}}
|
||||||
{{range $k, $line := $section.Lines}}
|
{{range $k, $line := $section.Lines}}
|
||||||
<tr class="{{DiffLineTypeToStr .GetType}}-code nl-{{$k}} ol-{{$k}}">
|
<tr class="{{DiffLineTypeToStr .Type}}-code nl-{{$k}} ol-{{$k}}">
|
||||||
{{if eq .GetType 4}}
|
{{if eq .Type 4}}
|
||||||
<td class="lines-num"></td>
|
<td class="lines-num"></td>
|
||||||
<td colspan="3" class="lines-code">
|
<td colspan="3" class="lines-code">
|
||||||
<pre><code class="{{if $highlightClass}}language-{{$highlightClass}}{{else}}nohighlight{{end}}">{{$section.ComputedInlineDiffFor $line}}</code></pre>
|
<pre><code class="{{if $highlightClass}}language-{{$highlightClass}}{{else}}nohighlight{{end}}">{{$section.ComputedInlineDiffFor $line}}</code></pre>
|
||||||
</td>
|
</td>
|
||||||
{{else}}
|
{{else}}
|
||||||
<td class="lines-num lines-num-old" {{if $line.LeftIdx}} id="diff-{{Sha1 $file.Index}}L{{$line.LeftIdx}}" data-line-number="{{$line.LeftIdx}}"{{end}}>
|
<td class="lines-num lines-num-old" {{if $line.LeftLine}} id="diff-{{Sha1 $file.Index}}L{{$line.LeftLine}}" data-line-number="{{$line.LeftLine}}"{{end}}>
|
||||||
</td>
|
</td>
|
||||||
<td class="lines-code halfwidth">
|
<td class="lines-code halfwidth">
|
||||||
<pre><code class="wrap {{if $highlightClass}}language-{{$highlightClass}}{{else}}nohighlight{{end}}">{{if $line.LeftIdx}}{{$section.ComputedInlineDiffFor $line}}{{end}}</code></pre>
|
<pre><code class="wrap {{if $highlightClass}}language-{{$highlightClass}}{{else}}nohighlight{{end}}">{{if $line.LeftLine}}{{$section.ComputedInlineDiffFor $line}}{{end}}</code></pre>
|
||||||
</td>
|
</td>
|
||||||
<td class="lines-num lines-num-new" {{if $line.RightIdx}} id="diff-{{Sha1 $file.Index}}R{{$line.RightIdx}}" data-line-number="{{$line.RightIdx}}"{{end}}>
|
<td class="lines-num lines-num-new" {{if $line.RightLine}} id="diff-{{Sha1 $file.Index}}R{{$line.RightLine}}" data-line-number="{{$line.RightLine}}"{{end}}>
|
||||||
</td>
|
</td>
|
||||||
<td class="lines-code halfwidth">
|
<td class="lines-code halfwidth">
|
||||||
<pre><code class="wrap {{if $highlightClass}}language-{{$highlightClass}}{{else}}nohighlight{{end}}">{{if $line.RightIdx}}{{$section.ComputedInlineDiffFor $line}}{{end}}</code></pre>
|
<pre><code class="wrap {{if $highlightClass}}language-{{$highlightClass}}{{else}}nohighlight{{end}}">{{if $line.RightLine}}{{$section.ComputedInlineDiffFor $line}}{{end}}</code></pre>
|
||||||
</td>
|
</td>
|
||||||
{{end}}
|
{{end}}
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -2,14 +2,14 @@
|
|||||||
{{$highlightClass := $file.HighlightClass}}
|
{{$highlightClass := $file.HighlightClass}}
|
||||||
{{range $j, $section := $file.Sections}}
|
{{range $j, $section := $file.Sections}}
|
||||||
{{range $k, $line := $section.Lines}}
|
{{range $k, $line := $section.Lines}}
|
||||||
<tr class="{{DiffLineTypeToStr .GetType}}-code nl-{{$k}} ol-{{$k}}">
|
<tr class="{{DiffLineTypeToStr .Type}}-code nl-{{$k}} ol-{{$k}}">
|
||||||
{{if eq .GetType 4}}
|
{{if eq .Type 4}}
|
||||||
<td colspan="2" class="lines-num">
|
<td colspan="2" class="lines-num">
|
||||||
{{/* {{if gt $j 0}}<span class="fold octicon octicon-fold"></span>{{end}} */}}
|
{{/* {{if gt $j 0}}<span class="fold octicon octicon-fold"></span>{{end}} */}}
|
||||||
</td>
|
</td>
|
||||||
{{else}}
|
{{else}}
|
||||||
<td class="lines-num lines-num-old" {{if $line.LeftIdx}} id="diff-{{$file.Index}}L{{$line.LeftIdx}}" data-line-number="{{$line.LeftIdx}}"{{end}}></td>
|
<td class="lines-num lines-num-old" {{if $line.LeftLine}} id="diff-{{$file.Index}}L{{$line.LeftLine}}" data-line-number="{{$line.LeftLine}}"{{end}}></td>
|
||||||
<td class="lines-num lines-num-new" {{if $line.RightIdx}} id="diff-{{$file.Index}}R{{$line.RightIdx}}" data-line-number="{{$line.RightIdx}}"{{end}}></td>
|
<td class="lines-num lines-num-new" {{if $line.RightLine}} id="diff-{{$file.Index}}R{{$line.RightLine}}" data-line-number="{{$line.RightLine}}"{{end}}></td>
|
||||||
{{end}}
|
{{end}}
|
||||||
<td class="lines-code">
|
<td class="lines-code">
|
||||||
<pre><code class="{{if $highlightClass}}language-{{$highlightClass}}{{else}}nohighlight{{end}}">{{$section.ComputedInlineDiffFor $line}}</code></pre>
|
<pre><code class="{{if $highlightClass}}language-{{$highlightClass}}{{else}}nohighlight{{end}}">{{$section.ComputedInlineDiffFor $line}}</code></pre>
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label for="content">{{$.i18n.Tr "repo.settings.githook_content"}}</label>
|
<label for="content">{{$.i18n.Tr "repo.settings.githook_content"}}</label>
|
||||||
<textarea id="content" name="content" wrap="off" autofocus>{{if .IsActive}}{{.Content}}{{else}}{{.Sample}}{{end}}</textarea>
|
<textarea id="content" name="content" wrap="off" autofocus>{{.Content}}</textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="inline field">
|
<div class="inline field">
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{{range .Hooks}}
|
{{range .Hooks}}
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<span class="text {{if .IsActive}}green{{else}}grey{{end}}"><i class="octicon octicon-primitive-dot"></i></span>
|
<span class="text {{if not .IsSample}}green{{else}}grey{{end}}"><i class="octicon octicon-primitive-dot"></i></span>
|
||||||
<span>{{.Name}}</span>
|
<span>{{.Name}}</span>
|
||||||
<a class="text blue ui right" href="{{$.RepoLink}}/settings/hooks/git/{{.Name}}"><i class="fa fa-pencil"></i></a>
|
<a class="text blue ui right" href="{{$.RepoLink}}/settings/hooks/git/{{.Name}}"><i class="fa fa-pencil"></i></a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -79,7 +79,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label for="mirror_address">{{.i18n.Tr "repo.mirror_address"}}</label>
|
<label for="mirror_address">{{.i18n.Tr "repo.mirror_address"}}</label>
|
||||||
<input id="mirror_address" name="mirror_address" value="{{.Mirror.FullAddress}}" required>
|
<input id="mirror_address" name="mirror_address" value="{{.Mirror.RawAddress}}" required>
|
||||||
<p class="help">{{.i18n.Tr "repo.mirror_address_desc"}}</p>
|
<p class="help">{{.i18n.Tr "repo.mirror_address_desc"}}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -23,35 +23,28 @@
|
|||||||
<td colspan="3"><i class="octicon octicon-mail-reply"></i><a href="{{EscapePound .BranchLink}}{{.ParentPath}}">..</a></td>
|
<td colspan="3"><i class="octicon octicon-mail-reply"></i><a href="{{EscapePound .BranchLink}}{{.ParentPath}}">..</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{range $item := .Files}}
|
{{range .Files}}
|
||||||
{{$entry := index $item 0}}
|
|
||||||
{{$commit := index $item 1}}
|
|
||||||
<tr>
|
<tr>
|
||||||
{{if $entry.IsSubModule}}
|
{{if .Submodule}}
|
||||||
<td>
|
<td>
|
||||||
<span class="octicon octicon-file-submodule"></span>
|
<span class="octicon octicon-file-submodule"></span>
|
||||||
{{$refURL := $commit.RefURL AppURL $.BranchLink}}
|
<a href="{{InferSubmoduleURL .Submodule}}">{{.Entry.Name}} @ {{ShortSHA1 .Submodule.Commit}}</a>
|
||||||
{{if $refURL}}
|
|
||||||
<a href="{{$refURL}}">{{$entry.Name}}</a> @ <a href="{{$refURL}}/commit/{{$commit.RefID}}">{{ShortSHA1 $commit.RefID}}</a>
|
|
||||||
{{else}}
|
|
||||||
{{$entry.Name}} @ {{ShortSHA1 $commit.RefID}}
|
|
||||||
{{end}}
|
|
||||||
</td>
|
</td>
|
||||||
{{else}}
|
{{else}}
|
||||||
<td class="name">
|
<td class="name">
|
||||||
{{if $entry.IsLink}}
|
{{if .Entry.IsSymlink}}
|
||||||
<span class="octicon octicon-file-symlink-file"></span>
|
<span class="octicon octicon-file-symlink-file"></span>
|
||||||
{{else}}
|
{{else}}
|
||||||
<span class="octicon octicon-file-{{if or $entry.IsDir}}directory{{else}}text{{end}}"></span>
|
<span class="octicon octicon-file-{{if or .Entry.IsTree}}directory{{else}}text{{end}}"></span>
|
||||||
{{end}}
|
{{end}}
|
||||||
<a href="{{EscapePound $.TreeLink}}/{{EscapePound $entry.Name}}">{{$entry.Name}}</a>
|
<a href="{{EscapePound $.TreeLink}}/{{EscapePound .Entry.Name}}">{{.Entry.Name}}</a>
|
||||||
</td>
|
</td>
|
||||||
{{end}}
|
{{end}}
|
||||||
<td class="message collapsing has-emoji">
|
<td class="message collapsing has-emoji">
|
||||||
<a rel="nofollow" class="ui sha label" href="{{$.RepoLink}}/commit/{{$commit.ID}}">{{ShortSHA1 $commit.ID.String}}</a>
|
<a rel="nofollow" class="ui sha label" href="{{$.RepoLink}}/commit/{{.Commit.ID}}">{{ShortSHA1 .Commit.ID.String}}</a>
|
||||||
{{RenderCommitMessage false $commit.Summary $.RepoLink $.Repository.ComposeMetas | Str2HTML}}
|
{{RenderCommitMessage false .Commit.Summary $.RepoLink $.Repository.ComposeMetas | Str2HTML}}
|
||||||
</td>
|
</td>
|
||||||
<td class="text grey right age">{{TimeSince $commit.Committer.When $.Lang}}</td>
|
<td class="text grey right age">{{TimeSince .Commit.Committer.When $.Lang}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{{end}}
|
{{end}}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
Reference in New Issue
Block a user