mirror of
https://github.com/go-gitea/gitea.git
synced 2025-11-03 08:02:36 +09:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
96c63a4937 | ||
|
|
459a2656bf | ||
|
|
a3b10538ec | ||
|
|
caee4870da | ||
|
|
8b2df7310b | ||
|
|
00ad4745ba | ||
|
|
c746f820ab | ||
|
|
f10640433f | ||
|
|
1ff480baa6 | ||
|
|
df941f5c39 | ||
|
|
1b10bc0cdf | ||
|
|
561f459364 | ||
|
|
1177a19a5b | ||
|
|
d1954ae4e7 | ||
|
|
7673ca9646 | ||
|
|
2d0db24083 | ||
|
|
dec663cc0a | ||
|
|
804148294a | ||
|
|
910e379265 | ||
|
|
f1720ad133 | ||
|
|
5f169bfcfd | ||
|
|
50adbb7134 |
27
CHANGELOG.md
27
CHANGELOG.md
@@ -4,6 +4,33 @@ This changelog goes through all the changes that have been made in each release
|
|||||||
without substantial changes to our git log; to see the highlights of what has
|
without substantial changes to our git log; to see the highlights of what has
|
||||||
been added to each release, please refer to the [blog](https://blog.gitea.io).
|
been added to each release, please refer to the [blog](https://blog.gitea.io).
|
||||||
|
|
||||||
|
## [1.4.3](https://github.com/go-gitea/gitea/releases/tag/v1.4.3) - 2018-06-26
|
||||||
|
* SECURITY
|
||||||
|
* HTML-escape plain-text READMEs (#4192) (#4214)
|
||||||
|
* Fix open redirect vulnerability on login screen (#4312) (#4312)
|
||||||
|
* BUGFIXES
|
||||||
|
* Fix broken monitoring page when running processes are shown (#4203) (#4208)
|
||||||
|
* Fix delete comment bug (#4216) (#4228)
|
||||||
|
* Delete reactions added to issues and comments when deleting repository (#4232) (#4237)
|
||||||
|
* Fix wiki URL encoding bug (#4091) (#4254)
|
||||||
|
* Fix code tab link when viewing tags (#3908) (#4263)
|
||||||
|
* Fix webhook type conflation (#4285) (#4285)
|
||||||
|
|
||||||
|
## [1.4.2](https://github.com/go-gitea/gitea/releases/tag/v1.4.2) - 2018-06-04
|
||||||
|
* BUGFIXES
|
||||||
|
* Adjust z-index for floating labels (#3939) (#3950)
|
||||||
|
* Add missing token validation on application settings page (#3976) #3978
|
||||||
|
* Webhook and hook_task clean up (#4006)
|
||||||
|
* Fix webhook bug of response info is not displayed in UI (#4023)
|
||||||
|
* Fix writer cannot read bare repo guide (#4033) (#4039)
|
||||||
|
* Don't force due date to current time (#3830) (#4057)
|
||||||
|
* Fix wiki redirects (#3919) (#4065)
|
||||||
|
* Fix attachment ENABLED (#4064) (#4066)
|
||||||
|
* Added deletion of an empty line at the end of file (#4054) (#4074)
|
||||||
|
* Use ResolveReference instead of path.Join (#4073)
|
||||||
|
* Fix #4081 Check for leading / in base before removing it (#4083)
|
||||||
|
* Respository's home page not updated after first push (#4075)
|
||||||
|
|
||||||
## [1.4.1](https://github.com/go-gitea/gitea/releases/tag/v1.4.1) - 2018-05-03
|
## [1.4.1](https://github.com/go-gitea/gitea/releases/tag/v1.4.1) - 2018-05-03
|
||||||
* BREAKING
|
* BREAKING
|
||||||
* Add "error" as reserved username (#3882) (#3886)
|
* Add "error" as reserved username (#3882) (#3886)
|
||||||
|
|||||||
@@ -403,7 +403,7 @@ ENABLE_FEDERATED_AVATAR = false
|
|||||||
|
|
||||||
[attachment]
|
[attachment]
|
||||||
; Whether attachments are enabled. Defaults to `true`
|
; Whether attachments are enabled. Defaults to `true`
|
||||||
ENABLE = true
|
ENABLED = true
|
||||||
; Path for attachments. Defaults to `data/attachments`
|
; Path for attachments. Defaults to `data/attachments`
|
||||||
PATH = data/attachments
|
PATH = data/attachments
|
||||||
; One or more allowed types, e.g. image/jpeg|image/png
|
; One or more allowed types, e.g. image/jpeg|image/png
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/git"
|
"code.gitea.io/git"
|
||||||
@@ -368,8 +369,15 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D
|
|||||||
a := line[beg+2 : middle]
|
a := line[beg+2 : middle]
|
||||||
b := line[middle+3:]
|
b := line[middle+3:]
|
||||||
if hasQuote {
|
if hasQuote {
|
||||||
a = string(git.UnescapeChars([]byte(a[1 : len(a)-1])))
|
var err error
|
||||||
b = string(git.UnescapeChars([]byte(b[1 : len(b)-1])))
|
a, err = strconv.Unquote(a)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Unquote: %v", err)
|
||||||
|
}
|
||||||
|
b, err = strconv.Unquote(b)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Unquote: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
curFile = &DiffFile{
|
curFile = &DiffFile{
|
||||||
|
|||||||
@@ -132,6 +132,10 @@ func (c *Comment) AfterLoad(session *xorm.Session) {
|
|||||||
|
|
||||||
// AfterDelete is invoked from XORM after the object is deleted.
|
// AfterDelete is invoked from XORM after the object is deleted.
|
||||||
func (c *Comment) AfterDelete() {
|
func (c *Comment) AfterDelete() {
|
||||||
|
if c.ID <= 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
_, err := DeleteAttachmentsByComment(c.ID, true)
|
_, err := DeleteAttachmentsByComment(c.ID, true)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -31,11 +31,6 @@ type Milestone struct {
|
|||||||
ClosedDateUnix util.TimeStamp
|
ClosedDateUnix util.TimeStamp
|
||||||
}
|
}
|
||||||
|
|
||||||
// BeforeInsert is invoked from XORM before inserting an object of this type.
|
|
||||||
func (m *Milestone) BeforeInsert() {
|
|
||||||
m.DeadlineUnix = util.TimeStampNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
// BeforeUpdate is invoked from XORM before updating this object.
|
// BeforeUpdate is invoked from XORM before updating this object.
|
||||||
func (m *Milestone) BeforeUpdate() {
|
func (m *Milestone) BeforeUpdate() {
|
||||||
if m.NumIssues > 0 {
|
if m.NumIssues > 0 {
|
||||||
|
|||||||
@@ -1822,6 +1822,8 @@ func DeleteRepository(doer *User, uid, repoID int64) error {
|
|||||||
&PullRequest{BaseRepoID: repoID},
|
&PullRequest{BaseRepoID: repoID},
|
||||||
&RepoUnit{RepoID: repoID},
|
&RepoUnit{RepoID: repoID},
|
||||||
&RepoRedirect{RedirectRepoID: repoID},
|
&RepoRedirect{RedirectRepoID: repoID},
|
||||||
|
&Webhook{RepoID: repoID},
|
||||||
|
&HookTask{RepoID: repoID},
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return fmt.Errorf("deleteBeans: %v", err)
|
return fmt.Errorf("deleteBeans: %v", err)
|
||||||
}
|
}
|
||||||
@@ -1844,6 +1846,9 @@ func DeleteRepository(doer *User, uid, repoID int64) error {
|
|||||||
if _, err = sess.In("issue_id", issueIDs).Delete(&IssueUser{}); err != nil {
|
if _, err = sess.In("issue_id", issueIDs).Delete(&IssueUser{}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if _, err = sess.In("issue_id", issueIDs).Delete(&Reaction{}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
attachments := make([]*Attachment, 0, 5)
|
attachments := make([]*Attachment, 0, 5)
|
||||||
if err = sess.
|
if err = sess.
|
||||||
|
|||||||
@@ -437,7 +437,14 @@ func (t *HookTask) AfterLoad() {
|
|||||||
|
|
||||||
t.RequestInfo = &HookRequest{}
|
t.RequestInfo = &HookRequest{}
|
||||||
if err := json.Unmarshal([]byte(t.RequestContent), t.RequestInfo); err != nil {
|
if err := json.Unmarshal([]byte(t.RequestContent), t.RequestInfo); err != nil {
|
||||||
log.Error(3, "Unmarshal[%d]: %v", t.ID, err)
|
log.Error(3, "Unmarshal RequestContent[%d]: %v", t.ID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(t.ResponseContent) > 0 {
|
||||||
|
t.ResponseInfo = &HookResponse{}
|
||||||
|
if err := json.Unmarshal([]byte(t.ResponseContent), t.ResponseInfo); err != nil {
|
||||||
|
log.Error(3, "Unmarshal ResponseContent[%d]: %v", t.ID, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -619,6 +626,10 @@ func (t *HookTask) deliver() {
|
|||||||
log.Trace("Hook delivery failed: %s", t.UUID)
|
log.Trace("Hook delivery failed: %s", t.UUID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := UpdateHookTask(t); err != nil {
|
||||||
|
log.Error(4, "UpdateHookTask [%d]: %v", t.ID, err)
|
||||||
|
}
|
||||||
|
|
||||||
// Update webhook last delivery status.
|
// Update webhook last delivery status.
|
||||||
w, err := GetWebhookByID(t.HookID)
|
w, err := GetWebhookByID(t.HookID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -671,10 +682,6 @@ func DeliverHooks() {
|
|||||||
// Update hook task status.
|
// Update hook task status.
|
||||||
for _, t := range tasks {
|
for _, t := range tasks {
|
||||||
t.deliver()
|
t.deliver()
|
||||||
|
|
||||||
if err := UpdateHookTask(t); err != nil {
|
|
||||||
log.Error(4, "UpdateHookTask [%d]: %v", t.ID, err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start listening on new hook requests.
|
// Start listening on new hook requests.
|
||||||
@@ -695,10 +702,6 @@ func DeliverHooks() {
|
|||||||
}
|
}
|
||||||
for _, t := range tasks {
|
for _, t := range tasks {
|
||||||
t.deliver()
|
t.deliver()
|
||||||
if err := UpdateHookTask(t); err != nil {
|
|
||||||
log.Error(4, "UpdateHookTask [%d]: %v", t.ID, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ func (f *AddKeyForm) Validate(ctx *macaron.Context, errs binding.Errors) binding
|
|||||||
|
|
||||||
// NewAccessTokenForm form for creating access token
|
// NewAccessTokenForm form for creating access token
|
||||||
type NewAccessTokenForm struct {
|
type NewAccessTokenForm struct {
|
||||||
Name string `binding:"Required"`
|
Name string `binding:"Required;MaxSize(255)"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate valideates the fields
|
// Validate valideates the fields
|
||||||
|
|||||||
@@ -114,16 +114,25 @@ func cutoutVerbosePrefix(prefix string) string {
|
|||||||
|
|
||||||
// URLJoin joins url components, like path.Join, but preserving contents
|
// URLJoin joins url components, like path.Join, but preserving contents
|
||||||
func URLJoin(base string, elems ...string) string {
|
func URLJoin(base string, elems ...string) string {
|
||||||
u, err := url.Parse(base)
|
if !strings.HasSuffix(base, "/") {
|
||||||
|
base += "/"
|
||||||
|
}
|
||||||
|
baseURL, err := url.Parse(base)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(4, "URLJoin: Invalid base URL %s", base)
|
log.Error(4, "URLJoin: Invalid base URL %s", base)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
joinArgs := make([]string, 0, len(elems)+1)
|
joinedPath := path.Join(elems...)
|
||||||
joinArgs = append(joinArgs, u.Path)
|
argURL, err := url.Parse(joinedPath)
|
||||||
joinArgs = append(joinArgs, elems...)
|
if err != nil {
|
||||||
u.Path = path.Join(joinArgs...)
|
log.Error(4, "URLJoin: Invalid arg %s", joinedPath)
|
||||||
return u.String()
|
return ""
|
||||||
|
}
|
||||||
|
joinedURL := baseURL.ResolveReference(argURL).String()
|
||||||
|
if !baseURL.IsAbs() && !strings.HasPrefix(base, "/") {
|
||||||
|
return joinedURL[1:] // Removing leading '/' if needed
|
||||||
|
}
|
||||||
|
return joinedURL
|
||||||
}
|
}
|
||||||
|
|
||||||
// RenderIssueIndexPatternOptions options for RenderIssueIndexPattern function
|
// RenderIssueIndexPatternOptions options for RenderIssueIndexPattern function
|
||||||
@@ -396,6 +405,9 @@ func RenderShortLinks(rawBytes []byte, urlPrefix string, noLink bool, isWikiMark
|
|||||||
} else {
|
} else {
|
||||||
link = strings.Replace(link, " ", "-", -1)
|
link = strings.Replace(link, " ", "-", -1)
|
||||||
}
|
}
|
||||||
|
if !strings.Contains(link, "/") {
|
||||||
|
link = url.PathEscape(link)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if image {
|
if image {
|
||||||
if !absoluteLink {
|
if !absoluteLink {
|
||||||
|
|||||||
@@ -83,6 +83,14 @@ func TestURLJoin(t *testing.T) {
|
|||||||
"a", "b/c/"),
|
"a", "b/c/"),
|
||||||
newTest("a/b/d",
|
newTest("a/b/d",
|
||||||
"a/", "b/c/", "/../d/"),
|
"a/", "b/c/", "/../d/"),
|
||||||
|
newTest("https://try.gitea.io/a/b/c#d",
|
||||||
|
"https://try.gitea.io", "a/b", "c#d"),
|
||||||
|
newTest("/a/b/d",
|
||||||
|
"/a/", "b/c/", "/../d/"),
|
||||||
|
newTest("/a/b/c",
|
||||||
|
"/a", "b/c/"),
|
||||||
|
newTest("/a/b/c#hash",
|
||||||
|
"/a", "b/c#hash"),
|
||||||
} {
|
} {
|
||||||
assert.Equal(t, test.Expected, URLJoin(test.Base, test.Elements...))
|
assert.Equal(t, test.Expected, URLJoin(test.Base, test.Elements...))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,10 +55,16 @@ func TestRender_ShortLinks(t *testing.T) {
|
|||||||
rawtree := markup.URLJoin(AppSubURL, "raw", "master")
|
rawtree := markup.URLJoin(AppSubURL, "raw", "master")
|
||||||
url := markup.URLJoin(tree, "Link")
|
url := markup.URLJoin(tree, "Link")
|
||||||
otherUrl := markup.URLJoin(tree, "OtherLink")
|
otherUrl := markup.URLJoin(tree, "OtherLink")
|
||||||
|
encodedURL := markup.URLJoin(tree, "Link%3F")
|
||||||
imgurl := markup.URLJoin(rawtree, "Link.jpg")
|
imgurl := markup.URLJoin(rawtree, "Link.jpg")
|
||||||
|
encodedImgurl := markup.URLJoin(rawtree, "Link+%23.jpg")
|
||||||
|
notencodedImgurl := markup.URLJoin(rawtree, "some", "path", "Link+#.jpg")
|
||||||
urlWiki := markup.URLJoin(AppSubURL, "wiki", "Link")
|
urlWiki := markup.URLJoin(AppSubURL, "wiki", "Link")
|
||||||
otherUrlWiki := markup.URLJoin(AppSubURL, "wiki", "OtherLink")
|
otherUrlWiki := markup.URLJoin(AppSubURL, "wiki", "OtherLink")
|
||||||
|
encodedURLWiki := markup.URLJoin(AppSubURL, "wiki", "Link%3F")
|
||||||
imgurlWiki := markup.URLJoin(AppSubURL, "wiki", "raw", "Link.jpg")
|
imgurlWiki := markup.URLJoin(AppSubURL, "wiki", "raw", "Link.jpg")
|
||||||
|
encodedImgurlWiki := markup.URLJoin(AppSubURL, "wiki", "raw", "Link+%23.jpg")
|
||||||
|
notencodedImgurlWiki := markup.URLJoin(AppSubURL, "wiki", "raw", "some", "path", "Link+#.jpg")
|
||||||
favicon := "http://google.com/favicon.ico"
|
favicon := "http://google.com/favicon.ico"
|
||||||
|
|
||||||
test(
|
test(
|
||||||
@@ -101,6 +107,26 @@ func TestRender_ShortLinks(t *testing.T) {
|
|||||||
"[[Link]] [[OtherLink]]",
|
"[[Link]] [[OtherLink]]",
|
||||||
`<p><a href="`+url+`" rel="nofollow">Link</a> <a href="`+otherUrl+`" rel="nofollow">OtherLink</a></p>`,
|
`<p><a href="`+url+`" rel="nofollow">Link</a> <a href="`+otherUrl+`" rel="nofollow">OtherLink</a></p>`,
|
||||||
`<p><a href="`+urlWiki+`" rel="nofollow">Link</a> <a href="`+otherUrlWiki+`" rel="nofollow">OtherLink</a></p>`)
|
`<p><a href="`+urlWiki+`" rel="nofollow">Link</a> <a href="`+otherUrlWiki+`" rel="nofollow">OtherLink</a></p>`)
|
||||||
|
test(
|
||||||
|
"[[Link?]]",
|
||||||
|
`<p><a href="`+encodedURL+`" rel="nofollow">Link?</a></p>`,
|
||||||
|
`<p><a href="`+encodedURLWiki+`" rel="nofollow">Link?</a></p>`)
|
||||||
|
test(
|
||||||
|
"[[Link]] [[OtherLink]] [[Link?]]",
|
||||||
|
`<p><a href="`+url+`" rel="nofollow">Link</a> <a href="`+otherUrl+`" rel="nofollow">OtherLink</a> <a href="`+encodedURL+`" rel="nofollow">Link?</a></p>`,
|
||||||
|
`<p><a href="`+urlWiki+`" rel="nofollow">Link</a> <a href="`+otherUrlWiki+`" rel="nofollow">OtherLink</a> <a href="`+encodedURLWiki+`" rel="nofollow">Link?</a></p>`)
|
||||||
|
test(
|
||||||
|
"[[Link #.jpg]]",
|
||||||
|
`<p><a href="`+encodedImgurl+`" rel="nofollow"><img src="`+encodedImgurl+`"/></a></p>`,
|
||||||
|
`<p><a href="`+encodedImgurlWiki+`" rel="nofollow"><img src="`+encodedImgurlWiki+`"/></a></p>`)
|
||||||
|
test(
|
||||||
|
"[[Name|Link #.jpg|alt=\"AltName\"|title='Title']]",
|
||||||
|
`<p><a href="`+encodedImgurl+`" rel="nofollow"><img src="`+encodedImgurl+`" alt="AltName" title="Title"/></a></p>`,
|
||||||
|
`<p><a href="`+encodedImgurlWiki+`" rel="nofollow"><img src="`+encodedImgurlWiki+`" alt="AltName" title="Title"/></a></p>`)
|
||||||
|
test(
|
||||||
|
"[[some/path/Link #.jpg]]",
|
||||||
|
`<p><a href="`+notencodedImgurl+`" rel="nofollow"><img src="`+notencodedImgurl+`"/></a></p>`,
|
||||||
|
`<p><a href="`+notencodedImgurlWiki+`" rel="nofollow"><img src="`+notencodedImgurlWiki+`"/></a></p>`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMisc_IsMarkdownFile(t *testing.T) {
|
func TestMisc_IsMarkdownFile(t *testing.T) {
|
||||||
|
|||||||
@@ -956,7 +956,7 @@ func NewContext() {
|
|||||||
AttachmentAllowedTypes = strings.Replace(sec.Key("ALLOWED_TYPES").MustString("image/jpeg,image/png,application/zip,application/gzip"), "|", ",", -1)
|
AttachmentAllowedTypes = strings.Replace(sec.Key("ALLOWED_TYPES").MustString("image/jpeg,image/png,application/zip,application/gzip"), "|", ",", -1)
|
||||||
AttachmentMaxSize = sec.Key("MAX_SIZE").MustInt64(4)
|
AttachmentMaxSize = sec.Key("MAX_SIZE").MustInt64(4)
|
||||||
AttachmentMaxFiles = sec.Key("MAX_FILES").MustInt(5)
|
AttachmentMaxFiles = sec.Key("MAX_FILES").MustInt(5)
|
||||||
AttachmentEnabled = sec.Key("ENABLE").MustBool(true)
|
AttachmentEnabled = sec.Key("ENABLED").MustBool(true)
|
||||||
|
|
||||||
TimeFormatKey := Cfg.Section("time").Key("FORMAT").MustString("RFC1123")
|
TimeFormatKey := Cfg.Section("time").Key("FORMAT").MustString("RFC1123")
|
||||||
TimeFormat = map[string]string{
|
TimeFormat = map[string]string{
|
||||||
|
|||||||
@@ -4,6 +4,15 @@
|
|||||||
|
|
||||||
package util
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
)
|
||||||
|
|
||||||
// OptionalBool a boolean that can be "null"
|
// OptionalBool a boolean that can be "null"
|
||||||
type OptionalBool byte
|
type OptionalBool byte
|
||||||
|
|
||||||
@@ -47,6 +56,41 @@ func Max(a, b int) int {
|
|||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// URLJoin joins url components, like path.Join, but preserving contents
|
||||||
|
func URLJoin(base string, elems ...string) string {
|
||||||
|
if !strings.HasSuffix(base, "/") {
|
||||||
|
base += "/"
|
||||||
|
}
|
||||||
|
baseURL, err := url.Parse(base)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(4, "URLJoin: Invalid base URL %s", base)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
joinedPath := path.Join(elems...)
|
||||||
|
argURL, err := url.Parse(joinedPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(4, "URLJoin: Invalid arg %s", joinedPath)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
joinedURL := baseURL.ResolveReference(argURL).String()
|
||||||
|
if !baseURL.IsAbs() && !strings.HasPrefix(base, "/") {
|
||||||
|
return joinedURL[1:] // Removing leading '/' if needed
|
||||||
|
}
|
||||||
|
return joinedURL
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsExternalURL checks if rawURL points to an external URL like http://example.com
|
||||||
|
func IsExternalURL(rawURL string) bool {
|
||||||
|
parsed, err := url.Parse(rawURL)
|
||||||
|
if err != nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if len(parsed.Host) != 0 && strings.Replace(parsed.Host, "www.", "", 1) != strings.Replace(setting.Domain, "www.", "", 1) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// Min min of two ints
|
// Min min of two ints
|
||||||
func Min(a, b int) int {
|
func Min(a, b int) int {
|
||||||
if a > b {
|
if a > b {
|
||||||
|
|||||||
79
modules/util/util_test.go
Normal file
79
modules/util/util_test.go
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
// Copyright 2018 The Gitea 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 util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestURLJoin(t *testing.T) {
|
||||||
|
type test struct {
|
||||||
|
Expected string
|
||||||
|
Base string
|
||||||
|
Elements []string
|
||||||
|
}
|
||||||
|
newTest := func(expected, base string, elements ...string) test {
|
||||||
|
return test{Expected: expected, Base: base, Elements: elements}
|
||||||
|
}
|
||||||
|
for _, test := range []test{
|
||||||
|
newTest("https://try.gitea.io/a/b/c",
|
||||||
|
"https://try.gitea.io", "a/b", "c"),
|
||||||
|
newTest("https://try.gitea.io/a/b/c",
|
||||||
|
"https://try.gitea.io/", "/a/b/", "/c/"),
|
||||||
|
newTest("https://try.gitea.io/a/c",
|
||||||
|
"https://try.gitea.io/", "/a/./b/", "../c/"),
|
||||||
|
newTest("a/b/c",
|
||||||
|
"a", "b/c/"),
|
||||||
|
newTest("a/b/d",
|
||||||
|
"a/", "b/c/", "/../d/"),
|
||||||
|
newTest("https://try.gitea.io/a/b/c#d",
|
||||||
|
"https://try.gitea.io", "a/b", "c#d"),
|
||||||
|
newTest("/a/b/d",
|
||||||
|
"/a/", "b/c/", "/../d/"),
|
||||||
|
newTest("/a/b/c",
|
||||||
|
"/a", "b/c/"),
|
||||||
|
newTest("/a/b/c#hash",
|
||||||
|
"/a", "b/c#hash"),
|
||||||
|
} {
|
||||||
|
assert.Equal(t, test.Expected, URLJoin(test.Base, test.Elements...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsExternalURL(t *testing.T) {
|
||||||
|
setting.Domain = "try.gitea.io"
|
||||||
|
type test struct {
|
||||||
|
Expected bool
|
||||||
|
RawURL string
|
||||||
|
}
|
||||||
|
newTest := func(expected bool, rawURL string) test {
|
||||||
|
return test{Expected: expected, RawURL: rawURL}
|
||||||
|
}
|
||||||
|
for _, test := range []test{
|
||||||
|
newTest(false,
|
||||||
|
"https://try.gitea.io"),
|
||||||
|
newTest(true,
|
||||||
|
"https://example.com/"),
|
||||||
|
newTest(true,
|
||||||
|
"//example.com"),
|
||||||
|
newTest(true,
|
||||||
|
"http://example.com"),
|
||||||
|
newTest(false,
|
||||||
|
"a/"),
|
||||||
|
newTest(false,
|
||||||
|
"https://try.gitea.io/test?param=false"),
|
||||||
|
newTest(false,
|
||||||
|
"test?param=false"),
|
||||||
|
newTest(false,
|
||||||
|
"//try.gitea.io/test?param=false"),
|
||||||
|
newTest(false,
|
||||||
|
"/hey/hey/hey#3244"),
|
||||||
|
} {
|
||||||
|
assert.Equal(t, test.Expected, IsExternalURL(test.RawURL))
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
@@ -152,6 +152,10 @@ pre, code {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.floating.label {
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
&.menu,
|
&.menu,
|
||||||
&.vertical.menu,
|
&.vertical.menu,
|
||||||
&.segment {
|
&.segment {
|
||||||
@@ -167,6 +171,14 @@ pre, code {
|
|||||||
font-size: .92857143rem;
|
font-size: .92857143rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.dropdown .menu>.item>.floating.label {
|
||||||
|
z-index: 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.dropdown .menu .menu>.item>.floating.label {
|
||||||
|
z-index: 21;
|
||||||
|
}
|
||||||
|
|
||||||
.text {
|
.text {
|
||||||
&.red {
|
&.red {
|
||||||
color: #d95c5c !important;
|
color: #d95c5c !important;
|
||||||
|
|||||||
@@ -105,7 +105,9 @@ func renderDirectory(ctx *context.Context, treeLink string) {
|
|||||||
ctx.Data["FileContent"] = string(markup.Render(readmeFile.Name(), buf, treeLink, ctx.Repo.Repository.ComposeMetas()))
|
ctx.Data["FileContent"] = string(markup.Render(readmeFile.Name(), buf, treeLink, ctx.Repo.Repository.ComposeMetas()))
|
||||||
} else {
|
} else {
|
||||||
ctx.Data["IsRenderedHTML"] = true
|
ctx.Data["IsRenderedHTML"] = true
|
||||||
ctx.Data["FileContent"] = string(bytes.Replace(buf, []byte("\n"), []byte(`<br>`), -1))
|
ctx.Data["FileContent"] = strings.Replace(
|
||||||
|
gotemplate.HTMLEscapeString(string(buf)), "\n", `<br>`, -1,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -208,7 +210,9 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
|
|||||||
ctx.Data["FileContent"] = string(markup.Render(blob.Name(), buf, path.Dir(treeLink), ctx.Repo.Repository.ComposeMetas()))
|
ctx.Data["FileContent"] = string(markup.Render(blob.Name(), buf, path.Dir(treeLink), ctx.Repo.Repository.ComposeMetas()))
|
||||||
} else if readmeExist {
|
} else if readmeExist {
|
||||||
ctx.Data["IsRenderedHTML"] = true
|
ctx.Data["IsRenderedHTML"] = true
|
||||||
ctx.Data["FileContent"] = string(bytes.Replace(buf, []byte("\n"), []byte(`<br>`), -1))
|
ctx.Data["FileContent"] = strings.Replace(
|
||||||
|
gotemplate.HTMLEscapeString(string(buf)), "\n", `<br>`, -1,
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
// 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
|
||||||
@@ -223,6 +227,10 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
|
|||||||
|
|
||||||
var output bytes.Buffer
|
var output bytes.Buffer
|
||||||
lines := strings.Split(fileContent, "\n")
|
lines := strings.Split(fileContent, "\n")
|
||||||
|
//Remove blank line at the end of file
|
||||||
|
if len(lines) > 0 && lines[len(lines)-1] == "" {
|
||||||
|
lines = lines[:len(lines)-1]
|
||||||
|
}
|
||||||
for index, line := range lines {
|
for index, line := range lines {
|
||||||
line = gotemplate.HTMLEscapeString(line)
|
line = gotemplate.HTMLEscapeString(line)
|
||||||
if index != len(lines)-1 {
|
if index != len(lines)-1 {
|
||||||
|
|||||||
@@ -205,7 +205,7 @@ func GogsHooksNewPost(ctx *context.Context, form auth.NewGogshookForm) {
|
|||||||
Secret: form.Secret,
|
Secret: form.Secret,
|
||||||
HookEvent: ParseHookEvent(form.WebhookForm),
|
HookEvent: ParseHookEvent(form.WebhookForm),
|
||||||
IsActive: form.Active,
|
IsActive: form.Active,
|
||||||
HookTaskType: models.GITEA,
|
HookTaskType: models.GOGS,
|
||||||
OrgID: orCtx.OrgID,
|
OrgID: orCtx.OrgID,
|
||||||
}
|
}
|
||||||
if err := w.UpdateEvent(); err != nil {
|
if err := w.UpdateEvent(); err != nil {
|
||||||
|
|||||||
@@ -350,7 +350,7 @@ func NewWikiPost(ctx *context.Context, form auth.NewWikiForm) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Redirect(ctx.Repo.RepoLink + "/wiki/" + models.WikiNameToFilename(wikiName))
|
ctx.Redirect(ctx.Repo.RepoLink + "/wiki/" + models.WikiNameToSubURL(wikiName))
|
||||||
}
|
}
|
||||||
|
|
||||||
// EditWiki render wiki modify page
|
// EditWiki render wiki modify page
|
||||||
@@ -391,7 +391,7 @@ func EditWikiPost(ctx *context.Context, form auth.NewWikiForm) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Redirect(ctx.Repo.RepoLink + "/wiki/" + models.WikiNameToFilename(newWikiName))
|
ctx.Redirect(ctx.Repo.RepoLink + "/wiki/" + models.WikiNameToSubURL(newWikiName))
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteWikiPagePost delete wiki page
|
// DeleteWikiPagePost delete wiki page
|
||||||
|
|||||||
@@ -446,7 +446,7 @@ func RegisterRoutes(m *macaron.Macaron) {
|
|||||||
m.Get("/:id", repo.WebHooksEdit)
|
m.Get("/:id", repo.WebHooksEdit)
|
||||||
m.Post("/:id/test", repo.TestWebhook)
|
m.Post("/:id/test", repo.TestWebhook)
|
||||||
m.Post("/gitea/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost)
|
m.Post("/gitea/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost)
|
||||||
m.Post("/gogs/:id", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksNewPost)
|
m.Post("/gogs/:id", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksEditPost)
|
||||||
m.Post("/slack/:id", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksEditPost)
|
m.Post("/slack/:id", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksEditPost)
|
||||||
m.Post("/discord/:id", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksEditPost)
|
m.Post("/discord/:id", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksEditPost)
|
||||||
m.Post("/dingtalk/:id", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost)
|
m.Post("/dingtalk/:id", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost)
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
"github.com/go-macaron/captcha"
|
"github.com/go-macaron/captcha"
|
||||||
"github.com/markbates/goth"
|
"github.com/markbates/goth"
|
||||||
@@ -343,7 +344,7 @@ func handleSignInFull(ctx *context.Context, u *models.User, remember bool, obeyR
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if redirectTo, _ := url.QueryUnescape(ctx.GetCookie("redirect_to")); len(redirectTo) > 0 {
|
if redirectTo, _ := url.QueryUnescape(ctx.GetCookie("redirect_to")); len(redirectTo) > 0 && !util.IsExternalURL(redirectTo) {
|
||||||
ctx.SetCookie("redirect_to", "", -1, setting.AppSubURL)
|
ctx.SetCookie("redirect_to", "", -1, setting.AppSubURL)
|
||||||
if obeyRedirect {
|
if obeyRedirect {
|
||||||
ctx.RedirectToFirst(redirectTo)
|
ctx.RedirectToFirst(redirectTo)
|
||||||
|
|||||||
@@ -49,8 +49,8 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td>{{.PID}}</td>
|
<td>{{.PID}}</td>
|
||||||
<td>{{.Description}}</td>
|
<td>{{.Description}}</td>
|
||||||
<td>{{.Start.FormatLong}}</td>
|
<td>{{DateFmtLong .Start}}</td>
|
||||||
<td>{{TimeSinceUnix .Start $.Lang}}</td>
|
<td>{{TimeSince .Start $.Lang}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{{end}}
|
{{end}}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<div class="ui grid">
|
<div class="ui grid">
|
||||||
<div class="sixteen wide column content">
|
<div class="sixteen wide column content">
|
||||||
{{template "base/alert" .}}
|
{{template "base/alert" .}}
|
||||||
{{if .IsRepositoryAdmin}}
|
{{if .IsRepositoryWriter}}
|
||||||
<h4 class="ui top attached header">
|
<h4 class="ui top attached header">
|
||||||
{{.i18n.Tr "repo.quick_guide"}}
|
{{.i18n.Tr "repo.quick_guide"}}
|
||||||
</h4>
|
</h4>
|
||||||
|
|||||||
@@ -48,7 +48,7 @@
|
|||||||
<div class="ui tabs container">
|
<div class="ui tabs container">
|
||||||
<div class="ui tabular stackable menu navbar">
|
<div class="ui tabular stackable menu navbar">
|
||||||
{{if .Repository.UnitEnabled $.UnitTypeCode}}
|
{{if .Repository.UnitEnabled $.UnitTypeCode}}
|
||||||
<a class="{{if .PageIsViewCode}}active{{end}} item" href="{{.RepoLink}}{{if (ne .BranchName .Repository.DefaultBranch)}}/src/branch/{{.BranchName}}{{end}}">
|
<a class="{{if .PageIsViewCode}}active{{end}} item" href="{{.RepoLink}}{{if (ne .BranchName .Repository.DefaultBranch)}}/src/{{.BranchNameSubURL}}{{end}}">
|
||||||
<i class="octicon octicon-code"></i> {{.i18n.Tr "repo.code"}}
|
<i class="octicon octicon-code"></i> {{.i18n.Tr "repo.code"}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|||||||
38
vendor/code.gitea.io/git/Gopkg.lock
generated
vendored
Normal file
38
vendor/code.gitea.io/git/Gopkg.lock
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||||
|
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/Unknwon/com"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "7677a1d7c1137cd3dd5ba7a076d0c898a1ef4520"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/davecgh/go-spew"
|
||||||
|
packages = ["spew"]
|
||||||
|
revision = "6d212800a42e8ab5c146b8ace3490ee17e5225f9"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/mcuadros/go-version"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "257f7b9a7d87427c8d7f89469a5958d57f8abd7c"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/pmezard/go-difflib"
|
||||||
|
packages = ["difflib"]
|
||||||
|
revision = "d8ed2627bdf02c080bf22230dbb337003b7aba2d"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/stretchr/testify"
|
||||||
|
packages = [
|
||||||
|
"assert",
|
||||||
|
"require"
|
||||||
|
]
|
||||||
|
revision = "976c720a22c8eb4eb6a0b4348ad85ad12491a506"
|
||||||
|
|
||||||
|
[solve-meta]
|
||||||
|
analyzer-name = "dep"
|
||||||
|
analyzer-version = 1
|
||||||
|
inputs-digest = "d37e90051cd58dd1f99f808626e82d64eac47f2b2334c6fcb9179bfcf2814622"
|
||||||
|
solver-name = "gps-cdcl"
|
||||||
|
solver-version = 1
|
||||||
34
vendor/code.gitea.io/git/Gopkg.toml
generated
vendored
Normal file
34
vendor/code.gitea.io/git/Gopkg.toml
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# Gopkg.toml
|
||||||
|
#
|
||||||
|
# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html
|
||||||
|
# for detailed Gopkg.toml documentation.
|
||||||
|
#
|
||||||
|
# required = ["github.com/user/thing/cmd/thing"]
|
||||||
|
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
||||||
|
#
|
||||||
|
# [[constraint]]
|
||||||
|
# name = "github.com/user/project"
|
||||||
|
# version = "1.0.0"
|
||||||
|
#
|
||||||
|
# [[constraint]]
|
||||||
|
# name = "github.com/user/project2"
|
||||||
|
# branch = "dev"
|
||||||
|
# source = "github.com/myfork/project2"
|
||||||
|
#
|
||||||
|
# [[override]]
|
||||||
|
# name = "github.com/x/y"
|
||||||
|
# version = "2.4.0"
|
||||||
|
#
|
||||||
|
# [prune]
|
||||||
|
# non-go = false
|
||||||
|
# go-tests = true
|
||||||
|
# unused-packages = true
|
||||||
|
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/Unknwon/com"
|
||||||
|
branch = "master"
|
||||||
|
|
||||||
|
[prune]
|
||||||
|
go-tests = true
|
||||||
|
unused-packages = true
|
||||||
1
vendor/code.gitea.io/git/MAINTAINERS
generated
vendored
1
vendor/code.gitea.io/git/MAINTAINERS
generated
vendored
@@ -18,3 +18,4 @@ Antoine Girard <sapk@sapk.fr> (@sapk)
|
|||||||
Jonas Östanbäck <jonas.ostanback@gmail.com> (@cez81)
|
Jonas Östanbäck <jonas.ostanback@gmail.com> (@cez81)
|
||||||
David Schneiderbauer <dschneiderbauer@gmail.com> (@daviian)
|
David Schneiderbauer <dschneiderbauer@gmail.com> (@daviian)
|
||||||
Peter Žeby <morlinest@gmail.com> (@morlinest)
|
Peter Žeby <morlinest@gmail.com> (@morlinest)
|
||||||
|
Jonas Franz <info@jonasfranz.software> (@JonasFranzDEV)
|
||||||
|
|||||||
10
vendor/code.gitea.io/git/error.go
generated
vendored
10
vendor/code.gitea.io/git/error.go
generated
vendored
@@ -40,6 +40,16 @@ func (err ErrNotExist) Error() string {
|
|||||||
return fmt.Sprintf("object does not exist [id: %s, rel_path: %s]", err.ID, err.RelPath)
|
return fmt.Sprintf("object does not exist [id: %s, rel_path: %s]", err.ID, err.RelPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ErrBadLink entry.FollowLink error
|
||||||
|
type ErrBadLink struct {
|
||||||
|
Name string
|
||||||
|
Message string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrBadLink) Error() string {
|
||||||
|
return fmt.Sprintf("%s: %s", err.Name, err.Message)
|
||||||
|
}
|
||||||
|
|
||||||
// ErrUnsupportedVersion error when required git version not matched
|
// ErrUnsupportedVersion error when required git version not matched
|
||||||
type ErrUnsupportedVersion struct {
|
type ErrUnsupportedVersion struct {
|
||||||
Required string
|
Required string
|
||||||
|
|||||||
81
vendor/code.gitea.io/git/parse.go
generated
vendored
Normal file
81
vendor/code.gitea.io/git/parse.go
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
// Copyright 2018 The Gitea 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 git
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ParseTreeEntries parses the output of a `git ls-tree` command.
|
||||||
|
func ParseTreeEntries(data []byte) ([]*TreeEntry, error) {
|
||||||
|
return parseTreeEntries(data, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseTreeEntries(data []byte, ptree *Tree) ([]*TreeEntry, error) {
|
||||||
|
entries := make([]*TreeEntry, 0, 10)
|
||||||
|
for pos := 0; pos < len(data); {
|
||||||
|
// expect line to be of the form "<mode> <type> <sha>\t<filename>"
|
||||||
|
entry := new(TreeEntry)
|
||||||
|
entry.ptree = ptree
|
||||||
|
if pos+6 > len(data) {
|
||||||
|
return nil, fmt.Errorf("Invalid ls-tree output: %s", string(data))
|
||||||
|
}
|
||||||
|
switch string(data[pos : pos+6]) {
|
||||||
|
case "100644":
|
||||||
|
entry.mode = EntryModeBlob
|
||||||
|
entry.Type = ObjectBlob
|
||||||
|
pos += 12 // skip over "100644 blob "
|
||||||
|
case "100755":
|
||||||
|
entry.mode = EntryModeExec
|
||||||
|
entry.Type = ObjectBlob
|
||||||
|
pos += 12 // skip over "100755 blob "
|
||||||
|
case "120000":
|
||||||
|
entry.mode = EntryModeSymlink
|
||||||
|
entry.Type = ObjectBlob
|
||||||
|
pos += 12 // skip over "120000 blob "
|
||||||
|
case "160000":
|
||||||
|
entry.mode = EntryModeCommit
|
||||||
|
entry.Type = ObjectCommit
|
||||||
|
pos += 14 // skip over "160000 object "
|
||||||
|
case "040000":
|
||||||
|
entry.mode = EntryModeTree
|
||||||
|
entry.Type = ObjectTree
|
||||||
|
pos += 12 // skip over "040000 tree "
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unknown type: %v", string(data[pos:pos+6]))
|
||||||
|
}
|
||||||
|
|
||||||
|
if pos+40 > len(data) {
|
||||||
|
return nil, fmt.Errorf("Invalid ls-tree output: %s", string(data))
|
||||||
|
}
|
||||||
|
id, err := NewIDFromString(string(data[pos : pos+40]))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Invalid ls-tree output: %v", err)
|
||||||
|
}
|
||||||
|
entry.ID = id
|
||||||
|
pos += 41 // skip over sha and trailing space
|
||||||
|
|
||||||
|
end := pos + bytes.IndexByte(data[pos:], '\n')
|
||||||
|
if end < pos {
|
||||||
|
return nil, fmt.Errorf("Invalid ls-tree output: %s", string(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
// In case entry name is surrounded by double quotes(it happens only in git-shell).
|
||||||
|
if data[pos] == '"' {
|
||||||
|
entry.name, err = strconv.Unquote(string(data[pos:end]))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Invalid ls-tree output: %v", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
entry.name = string(data[pos:end])
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = end + 1
|
||||||
|
entries = append(entries, entry)
|
||||||
|
}
|
||||||
|
return entries, nil
|
||||||
|
}
|
||||||
16
vendor/code.gitea.io/git/repo_blame.go
generated
vendored
16
vendor/code.gitea.io/git/repo_blame.go
generated
vendored
@@ -4,7 +4,21 @@
|
|||||||
|
|
||||||
package git
|
package git
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
// FileBlame return the Blame object of file
|
// FileBlame return the Blame object of file
|
||||||
func (repo *Repository) FileBlame(revision, path, file string) ([]byte, error) {
|
func (repo *Repository) FileBlame(revision, path, file string) ([]byte, error) {
|
||||||
return NewCommand("blame", "--root", file).RunInDirBytes(path)
|
return NewCommand("blame", "--root", "--", file).RunInDirBytes(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LineBlame returns the latest commit at the given line
|
||||||
|
func (repo *Repository) LineBlame(revision, path, file string, line uint) (*Commit, error) {
|
||||||
|
res, err := NewCommand("blame", fmt.Sprintf("-L %d,%d", line, line), "-p", revision, "--", file).RunInDir(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(res) < 40 {
|
||||||
|
return nil, fmt.Errorf("invalid result of blame: %s", res)
|
||||||
|
}
|
||||||
|
return repo.GetCommit(string(res[:40]))
|
||||||
}
|
}
|
||||||
|
|||||||
30
vendor/code.gitea.io/git/repo_commit.go
generated
vendored
30
vendor/code.gitea.io/git/repo_commit.go
generated
vendored
@@ -9,6 +9,8 @@ import (
|
|||||||
"container/list"
|
"container/list"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/mcuadros/go-version"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetRefCommitID returns the last commit ID string of given reference (branch or tag).
|
// GetRefCommitID returns the last commit ID string of given reference (branch or tag).
|
||||||
@@ -316,15 +318,35 @@ func (repo *Repository) getCommitsBeforeLimit(id SHA1, num int) (*list.List, err
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (repo *Repository) getBranches(commit *Commit, limit int) ([]string, error) {
|
func (repo *Repository) getBranches(commit *Commit, limit int) ([]string, error) {
|
||||||
stdout, err := NewCommand("for-each-ref", "--count="+ strconv.Itoa(limit), "--format=%(refname)", "--contains", commit.ID.String(), BranchPrefix).RunInDir(repo.Path)
|
if version.Compare(gitVersion, "2.7.0", ">=") {
|
||||||
|
stdout, err := NewCommand("for-each-ref", "--count="+strconv.Itoa(limit), "--format=%(refname:strip=2)", "--contains", commit.ID.String(), BranchPrefix).RunInDir(repo.Path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
branches := strings.Fields(stdout)
|
||||||
|
return branches, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
stdout, err := NewCommand("branch", "--contains", commit.ID.String()).RunInDir(repo.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
refs := strings.Split(stdout, "\n")
|
refs := strings.Split(stdout, "\n")
|
||||||
branches := make([]string, len(refs)-1)
|
|
||||||
for i, ref := range refs[:len(refs)-1] {
|
var max int
|
||||||
branches[i] = strings.TrimPrefix(ref, BranchPrefix)
|
if len(refs) > limit {
|
||||||
|
max = limit
|
||||||
|
} else {
|
||||||
|
max = len(refs) - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
branches := make([]string, max)
|
||||||
|
for i, ref := range refs[:max] {
|
||||||
|
parts := strings.Fields(ref)
|
||||||
|
|
||||||
|
branches[i] = parts[len(parts)-1]
|
||||||
}
|
}
|
||||||
return branches, nil
|
return branches, nil
|
||||||
}
|
}
|
||||||
|
|||||||
29
vendor/code.gitea.io/git/sha1.go
generated
vendored
29
vendor/code.gitea.io/git/sha1.go
generated
vendored
@@ -5,6 +5,7 @@
|
|||||||
package git
|
package git
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -26,43 +27,23 @@ func (id SHA1) Equal(s2 interface{}) bool {
|
|||||||
}
|
}
|
||||||
return v == id.String()
|
return v == id.String()
|
||||||
case []byte:
|
case []byte:
|
||||||
if len(v) != 20 {
|
return bytes.Equal(v, id[:])
|
||||||
return false
|
|
||||||
}
|
|
||||||
for i, v := range v {
|
|
||||||
if id[i] != v {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case SHA1:
|
case SHA1:
|
||||||
for i, v := range v {
|
return v == id
|
||||||
if id[i] != v {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns string (hex) representation of the Oid.
|
// String returns string (hex) representation of the Oid.
|
||||||
func (id SHA1) String() string {
|
func (id SHA1) String() string {
|
||||||
result := make([]byte, 0, 40)
|
return hex.EncodeToString(id[:])
|
||||||
hexvalues := []byte("0123456789abcdef")
|
|
||||||
for i := 0; i < 20; i++ {
|
|
||||||
result = append(result, hexvalues[id[i]>>4])
|
|
||||||
result = append(result, hexvalues[id[i]&0xf])
|
|
||||||
}
|
|
||||||
return string(result)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MustID always creates a new SHA1 from a [20]byte array with no validation of input.
|
// MustID always creates a new SHA1 from a [20]byte array with no validation of input.
|
||||||
func MustID(b []byte) SHA1 {
|
func MustID(b []byte) SHA1 {
|
||||||
var id SHA1
|
var id SHA1
|
||||||
for i := 0; i < 20; i++ {
|
copy(id[:], b)
|
||||||
id[i] = b[i]
|
|
||||||
}
|
|
||||||
return id
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
83
vendor/code.gitea.io/git/tree.go
generated
vendored
83
vendor/code.gitea.io/git/tree.go
generated
vendored
@@ -5,8 +5,6 @@
|
|||||||
package git
|
package git
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -30,84 +28,6 @@ func NewTree(repo *Repository, id SHA1) *Tree {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var escapeChar = []byte("\\")
|
|
||||||
|
|
||||||
// UnescapeChars reverses escaped characters.
|
|
||||||
func UnescapeChars(in []byte) []byte {
|
|
||||||
if bytes.Index(in, escapeChar) == -1 {
|
|
||||||
return in
|
|
||||||
}
|
|
||||||
|
|
||||||
endIdx := len(in) - 1
|
|
||||||
isEscape := false
|
|
||||||
out := make([]byte, 0, endIdx+1)
|
|
||||||
for i := range in {
|
|
||||||
if in[i] == '\\' && !isEscape {
|
|
||||||
isEscape = true
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
isEscape = false
|
|
||||||
out = append(out, in[i])
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseTreeData parses tree information from the (uncompressed) raw
|
|
||||||
// data from the tree object.
|
|
||||||
func parseTreeData(tree *Tree, data []byte) ([]*TreeEntry, error) {
|
|
||||||
entries := make([]*TreeEntry, 0, 10)
|
|
||||||
l := len(data)
|
|
||||||
pos := 0
|
|
||||||
for pos < l {
|
|
||||||
entry := new(TreeEntry)
|
|
||||||
entry.ptree = tree
|
|
||||||
step := 6
|
|
||||||
switch string(data[pos : pos+step]) {
|
|
||||||
case "100644":
|
|
||||||
entry.mode = EntryModeBlob
|
|
||||||
entry.Type = ObjectBlob
|
|
||||||
case "100755":
|
|
||||||
entry.mode = EntryModeExec
|
|
||||||
entry.Type = ObjectBlob
|
|
||||||
case "120000":
|
|
||||||
entry.mode = EntryModeSymlink
|
|
||||||
entry.Type = ObjectBlob
|
|
||||||
case "160000":
|
|
||||||
entry.mode = EntryModeCommit
|
|
||||||
entry.Type = ObjectCommit
|
|
||||||
|
|
||||||
step = 8
|
|
||||||
case "040000":
|
|
||||||
entry.mode = EntryModeTree
|
|
||||||
entry.Type = ObjectTree
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("unknown type: %v", string(data[pos:pos+step]))
|
|
||||||
}
|
|
||||||
pos += step + 6 // Skip string type of entry type.
|
|
||||||
|
|
||||||
step = 40
|
|
||||||
id, err := NewIDFromString(string(data[pos : pos+step]))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
entry.ID = id
|
|
||||||
pos += step + 1 // Skip half of SHA1.
|
|
||||||
|
|
||||||
step = bytes.IndexByte(data[pos:], '\n')
|
|
||||||
|
|
||||||
// In case entry name is surrounded by double quotes(it happens only in git-shell).
|
|
||||||
if data[pos] == '"' {
|
|
||||||
entry.name = string(UnescapeChars(data[pos+1 : pos+step-1]))
|
|
||||||
} else {
|
|
||||||
entry.name = string(data[pos : pos+step])
|
|
||||||
}
|
|
||||||
|
|
||||||
pos += step + 1
|
|
||||||
entries = append(entries, entry)
|
|
||||||
}
|
|
||||||
return entries, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SubTree get a sub tree by the sub dir path
|
// SubTree get a sub tree by the sub dir path
|
||||||
func (t *Tree) SubTree(rpath string) (*Tree, error) {
|
func (t *Tree) SubTree(rpath string) (*Tree, error) {
|
||||||
if len(rpath) == 0 {
|
if len(rpath) == 0 {
|
||||||
@@ -142,12 +62,11 @@ func (t *Tree) ListEntries() (Entries, error) {
|
|||||||
if t.entriesParsed {
|
if t.entriesParsed {
|
||||||
return t.entries, nil
|
return t.entries, nil
|
||||||
}
|
}
|
||||||
t.entriesParsed = true
|
|
||||||
|
|
||||||
stdout, err := NewCommand("ls-tree", t.ID.String()).RunInDirBytes(t.repo.Path)
|
stdout, err := NewCommand("ls-tree", t.ID.String()).RunInDirBytes(t.repo.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
t.entries, err = parseTreeData(t, stdout)
|
t.entries, err = parseTreeEntries(stdout, t)
|
||||||
return t.entries, err
|
return t.entries, err
|
||||||
}
|
}
|
||||||
|
|||||||
40
vendor/code.gitea.io/git/tree_entry.go
generated
vendored
40
vendor/code.gitea.io/git/tree_entry.go
generated
vendored
@@ -5,6 +5,7 @@
|
|||||||
package git
|
package git
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -90,6 +91,45 @@ func (te *TreeEntry) Blob() *Blob {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FollowLink returns the entry pointed to by a symlink
|
||||||
|
func (te *TreeEntry) FollowLink() (*TreeEntry, error) {
|
||||||
|
if !te.IsLink() {
|
||||||
|
return nil, ErrBadLink{te.Name(), "not a symlink"}
|
||||||
|
}
|
||||||
|
|
||||||
|
// read the link
|
||||||
|
r, err := te.Blob().Data()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
buf := make([]byte, te.Size())
|
||||||
|
_, err = io.ReadFull(r, buf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
lnk := string(buf)
|
||||||
|
t := te.ptree
|
||||||
|
|
||||||
|
// traverse up directories
|
||||||
|
for ; t != nil && strings.HasPrefix(lnk, "../"); lnk = lnk[3:] {
|
||||||
|
t = t.ptree
|
||||||
|
}
|
||||||
|
|
||||||
|
if t == nil {
|
||||||
|
return nil, ErrBadLink{te.Name(), "points outside of repo"}
|
||||||
|
}
|
||||||
|
|
||||||
|
target, err := t.GetTreeEntryByPath(lnk)
|
||||||
|
if err != nil {
|
||||||
|
if IsErrNotExist(err) {
|
||||||
|
return nil, ErrBadLink{te.Name(), "broken link"}
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return target, nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetSubJumpablePathName return the full path of subdirectory jumpable ( contains only one directory )
|
// GetSubJumpablePathName return the full path of subdirectory jumpable ( contains only one directory )
|
||||||
func (te *TreeEntry) GetSubJumpablePathName() string {
|
func (te *TreeEntry) GetSubJumpablePathName() string {
|
||||||
if te.IsSubModule() || !te.IsDir() {
|
if te.IsSubModule() || !te.IsDir() {
|
||||||
|
|||||||
6
vendor/vendor.json
vendored
6
vendor/vendor.json
vendored
@@ -3,10 +3,10 @@
|
|||||||
"ignore": "test appengine",
|
"ignore": "test appengine",
|
||||||
"package": [
|
"package": [
|
||||||
{
|
{
|
||||||
"checksumSHA1": "Gz+a5Qo4PCiB/Gf2f02v8HEAxDM=",
|
"checksumSHA1": "xwQNnA5geMAdbiBjBABtsjqZZMw=",
|
||||||
"path": "code.gitea.io/git",
|
"path": "code.gitea.io/git",
|
||||||
"revision": "6798d0f202cdc7187c00a467b586a4bdee27e8c9",
|
"revision": "31f4b8e8c805438ac6d8914b38accb1d8aaf695e",
|
||||||
"revisionTime": "2018-01-14T14:37:32Z"
|
"revisionTime": "2018-05-26T05:17:21Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "Qtq0kW+BnpYMOriaoCjMa86WGG8=",
|
"checksumSHA1": "Qtq0kW+BnpYMOriaoCjMa86WGG8=",
|
||||||
|
|||||||
Reference in New Issue
Block a user