diff --git a/.drone.yml b/.drone.yml index 6d9cde5ca9539..ec90c158b10dd 100644 --- a/.drone.yml +++ b/.drone.yml @@ -7,6 +7,9 @@ pipeline: image: docker:git commands: - git fetch --tags --force + when: + event: + exclude: [ pull_request ] download_translations: image: jonasfranz/crowdin @@ -71,12 +74,10 @@ pipeline: commands: - make clean - make generate - - make vet - - make lint - - make fmt-check + - make golangci-lint + - make revive - make swagger-check - make swagger-validate - - make misspell-check - make test-vendor - make build when: diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000000000..82d0e46694e1d --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,97 @@ +linters: + enable: + - gosimple + - deadcode + - typecheck + - govet + - errcheck + - staticcheck + - unused + - structcheck + - varcheck + - golint + - dupl + #- gocyclo # The cyclomatic complexety of a lot of functions is too high, we should refactor those another time. + - gofmt + - misspell + - gocritic + enable-all: false + disable-all: true + fast: false + +linters-settings: + gocritic: + disabled-checks: + - ifElseChain + - singleCaseSwitch # Every time this occured in the code, there was no other way. + +issues: + exclude-rules: + # Exclude some linters from running on tests files. + - path: _test\.go + linters: + - gocyclo + - errcheck + - dupl + - gosec + - unparam + - staticcheck + - path: models/migrations/v + linters: + - gocyclo + - errcheck + - dupl + - gosec + - linters: + - dupl + text: "webhook" + - linters: + - gocritic + text: "`ID' should not be capitalized" + - path: modules/templates/helper.go + linters: + - gocritic + - linters: + - unused + - deadcode + text: "swagger" + - path: contrib/pr/checkout.go + linters: + - errcheck + - path: models/issue.go + linters: + - errcheck + - path: models/migrations/ + linters: + - errcheck + - path: modules/log/ + linters: + - errcheck + - path: routers/routes/routes.go + linters: + - dupl + - path: routers/repo/view.go + linters: + - dupl + - path: models/migrations/ + linters: + - unused + - linters: + - staticcheck + text: "argument x is overwritten before first use" + - path: modules/httplib/httplib.go + linters: + - staticcheck + # Enabling this would require refactoring the methods and how they are called. + - path: models/issue_comment_list.go + linters: + - dupl + # "Destroy" is misspelled in github.com/go-macaron/session/session.go:213 so it's not our responsability to fix it + - path: modules/session/virtual.go + linters: + - misspell + text: '`Destory` is a misspelling of `Destroy`' + - path: modules/session/memory.go + linters: + - misspell + text: '`Destory` is a misspelling of `Destroy`' diff --git a/Makefile b/Makefile index f175b95ae14b2..56fa863c8e790 100644 --- a/Makefile +++ b/Makefile @@ -135,6 +135,10 @@ errcheck: .PHONY: lint lint: + @echo 'make lint is depricated. Use "make revive" if you want to use the old lint tool, or "make golangci-lint" to run a complete code check.' + +.PHONY: revive +revive: @hash revive > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ $(GO) get -u github.com/mgechev/revive; \ fi @@ -461,3 +465,11 @@ generate-images: .PHONY: pr pr: $(GO) run contrib/pr/checkout.go $(PR) + +.PHONY: golangci-lint +golangci-lint: + @hash golangci-lint > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ + export BINARY="golangci-lint"; \ + curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(GOPATH)/bin v1.16.0; \ + fi + golangci-lint run diff --git a/cmd/admin.go b/cmd/admin.go index ecb4eb48a6dc3..6234ab828db8d 100644 --- a/cmd/admin.go +++ b/cmd/admin.go @@ -481,7 +481,7 @@ func runUpdateOauth(c *cli.Context) error { } // update custom URL mapping - var customURLMapping *oauth2.CustomURLMapping + var customURLMapping = &oauth2.CustomURLMapping{} if oAuth2Config.CustomURLMapping != nil { customURLMapping.TokenURL = oAuth2Config.CustomURLMapping.TokenURL diff --git a/cmd/cert.go b/cmd/cert.go index 46473c0042e72..b62319f80854a 100644 --- a/cmd/cert.go +++ b/cmd/cert.go @@ -170,17 +170,28 @@ func runCert(c *cli.Context) error { if err != nil { log.Fatalf("Failed to open cert.pem for writing: %v", err) } - pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) - certOut.Close() + err = pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) + if err != nil { + log.Fatalf("Failed to encode certificate: %v", err) + } + err = certOut.Close() + if err != nil { + log.Fatalf("Failed to write cert: %v", err) + } log.Println("Written cert.pem") keyOut, err := os.OpenFile("key.pem", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) if err != nil { log.Fatalf("Failed to open key.pem for writing: %v", err) } - pem.Encode(keyOut, pemBlockForKey(priv)) - keyOut.Close() + err = pem.Encode(keyOut, pemBlockForKey(priv)) + if err != nil { + log.Fatalf("Failed to encode key: %v", err) + } + err = keyOut.Close() + if err != nil { + log.Fatalf("Failed to write key: %v", err) + } log.Println("Written key.pem") - return nil } diff --git a/cmd/convert.go b/cmd/convert.go new file mode 100644 index 0000000000000..cb0510c722fc8 --- /dev/null +++ b/cmd/convert.go @@ -0,0 +1,49 @@ +// Copyright 2019 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 cmd + +import ( + "fmt" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + + "github.com/urfave/cli" +) + +// CmdConvert represents the available convert sub-command. +var CmdConvert = cli.Command{ + Name: "convert", + Usage: "Convert the database", + Description: "A command to convert an existing MySQL database from utf8 to utf8mb4", + Action: runConvert, +} + +func runConvert(ctx *cli.Context) error { + if err := initDB(); err != nil { + return err + } + + log.Trace("AppPath: %s", setting.AppPath) + log.Trace("AppWorkPath: %s", setting.AppWorkPath) + log.Trace("Custom path: %s", setting.CustomPath) + log.Trace("Log path: %s", setting.LogRootPath) + models.LoadConfigs() + + if models.DbCfg.Type != "mysql" { + fmt.Println("This command can only be used with a MySQL database") + return nil + } + + if err := models.ConvertUtf8ToUtf8mb4(); err != nil { + log.Fatal("Failed to convert database from utf8 to utf8mb4: %v", err) + return err + } + + fmt.Println("Converted successfully, please confirm your database's character set is now utf8mb4") + + return nil +} diff --git a/cmd/serv.go b/cmd/serv.go index edfa88d60783d..59392800913c7 100644 --- a/cmd/serv.go +++ b/cmd/serv.go @@ -30,7 +30,6 @@ import ( ) const ( - accessDenied = "Repository does not exist or you do not have access" lfsAuthenticateVerb = "git-lfs-authenticate" ) @@ -67,7 +66,7 @@ func checkLFSVersion() { } func setup(logPath string) { - log.DelLogger("console") + _ = log.DelLogger("console") setting.NewContext() checkLFSVersion() } @@ -112,7 +111,9 @@ func runServ(c *cli.Context) error { } if len(c.Args()) < 1 { - cli.ShowSubcommandHelp(c) + if err := cli.ShowSubcommandHelp(c); err != nil { + fmt.Printf("error showing subcommand help: %v\n", err) + } return nil } @@ -209,7 +210,7 @@ func runServ(c *cli.Context) error { os.Setenv(models.EnvRepoIsWiki, strconv.FormatBool(results.IsWiki)) os.Setenv(models.EnvRepoName, results.RepoName) os.Setenv(models.EnvRepoUsername, results.OwnerName) - os.Setenv(models.EnvPusherName, username) + os.Setenv(models.EnvPusherName, results.UserName) os.Setenv(models.EnvPusherID, strconv.FormatInt(results.UserID, 10)) os.Setenv(models.ProtectedBranchRepoID, strconv.FormatInt(results.RepoID, 10)) os.Setenv(models.ProtectedBranchPRID, fmt.Sprintf("%d", 0)) diff --git a/cmd/web.go b/cmd/web.go index e6d0300a15504..e211674b4d713 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -178,11 +178,16 @@ func runWeb(ctx *cli.Context) error { } err = runHTTPS(listenAddr, setting.CertFile, setting.KeyFile, context2.ClearHandler(m)) case setting.FCGI: - listener, err := net.Listen("tcp", listenAddr) + var listener net.Listener + listener, err = net.Listen("tcp", listenAddr) if err != nil { log.Fatal("Failed to bind %s: %v", listenAddr, err) } - defer listener.Close() + defer func() { + if err := listener.Close(); err != nil { + log.Fatal("Failed to stop server: %v", err) + } + }() err = fcgi.Serve(listener, context2.ClearHandler(m)) case setting.UnixSocket: if err := os.Remove(listenAddr); err != nil && !os.IsNotExist(err) { diff --git a/contrib/pr/checkout.go b/contrib/pr/checkout.go index 880c029510c23..a837cb5812a08 100644 --- a/contrib/pr/checkout.go +++ b/contrib/pr/checkout.go @@ -91,8 +91,7 @@ func runPR() { routers.NewServices() //x, err = xorm.NewEngine("sqlite3", "file::memory:?cache=shared") - var helper testfixtures.Helper - helper = &testfixtures.SQLite{} + var helper testfixtures.Helper = &testfixtures.SQLite{} models.NewEngine(func(_ *xorm.Engine) error { return nil }) diff --git a/docs/content/doc/usage/command-line.en-us.md b/docs/content/doc/usage/command-line.en-us.md index ab52109e93584..516e46ff0bf20 100644 --- a/docs/content/doc/usage/command-line.en-us.md +++ b/docs/content/doc/usage/command-line.en-us.md @@ -62,6 +62,7 @@ Admin operations: - `--password value`: Password. Required. - `--email value`: Email. Required. - `--admin`: If provided, this makes the user an admin. Optional. + - `--access-token`: If provided, an access token will be created for the user. Optional. (default: false). - `--must-change-password`: If provided, the created user will be required to choose a newer password after the initial login. Optional. (default: true). - ``--random-password``: If provided, a randomly generated password will be used as the password of diff --git a/integrations/api_repo_file_content_test.go b/integrations/api_repo_file_content_test.go index 896d811083fb8..7a6025d423eb1 100644 --- a/integrations/api_repo_file_content_test.go +++ b/integrations/api_repo_file_content_test.go @@ -11,7 +11,6 @@ import ( "testing" "code.gitea.io/gitea/models" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" @@ -98,7 +97,7 @@ func testAPIGetFileContents(t *testing.T, u *url.URL) { resp = session.MakeRequest(t, req, http.StatusInternalServerError) expectedAPIError := context.APIError{ Message: "object does not exist [id: " + branch + ", rel_path: ]", - URL: base.DocURL, + URL: setting.API.SwaggerURL, } var apiError context.APIError DecodeJSON(t, resp, &apiError) diff --git a/integrations/api_repo_file_create_test.go b/integrations/api_repo_file_create_test.go index 28097179a060d..973ed9dfa595a 100644 --- a/integrations/api_repo_file_create_test.go +++ b/integrations/api_repo_file_create_test.go @@ -13,7 +13,6 @@ import ( "testing" "code.gitea.io/gitea/models" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/setting" @@ -146,8 +145,8 @@ func TestAPICreateFile(t *testing.T) { var fileResponse api.FileResponse DecodeJSON(t, resp, &fileResponse) expectedSHA := "a635aa942442ddfdba07468cf9661c08fbdf0ebf" - expectedHTMLURL := fmt.Sprintf("http://localhost:"+setting.HTTPPort+"/user2/repo1/blob/new_branch/new/file%d.txt", fileID) - expectedDownloadURL := fmt.Sprintf("http://localhost:"+setting.HTTPPort+"/user2/repo1/raw/branch/new_branch/new/file%d.txt", fileID) + expectedHTMLURL := fmt.Sprintf(setting.AppURL+"user2/repo1/blob/new_branch/new/file%d.txt", fileID) + expectedDownloadURL := fmt.Sprintf(setting.AppURL+"user2/repo1/raw/branch/new_branch/new/file%d.txt", fileID) assert.EqualValues(t, expectedSHA, fileResponse.Content.SHA) assert.EqualValues(t, expectedHTMLURL, fileResponse.Content.HTMLURL) assert.EqualValues(t, expectedDownloadURL, fileResponse.Content.DownloadURL) @@ -160,7 +159,7 @@ func TestAPICreateFile(t *testing.T) { resp = session.MakeRequest(t, req, http.StatusInternalServerError) expectedAPIError := context.APIError{ Message: "repository file already exists [path: " + treePath + "]", - URL: base.DocURL, + URL: setting.API.SwaggerURL, } var apiError context.APIError DecodeJSON(t, resp, &apiError) diff --git a/integrations/api_repo_file_delete_test.go b/integrations/api_repo_file_delete_test.go index e9029a669b977..2f5f9028a81a0 100644 --- a/integrations/api_repo_file_delete_test.go +++ b/integrations/api_repo_file_delete_test.go @@ -11,8 +11,8 @@ import ( "testing" "code.gitea.io/gitea/models" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "github.com/stretchr/testify/assert" @@ -102,7 +102,7 @@ func TestAPIDeleteFile(t *testing.T) { resp = session.MakeRequest(t, req, http.StatusInternalServerError) expectedAPIError := context.APIError{ Message: "sha does not match [given: " + deleteFileOptions.SHA + ", expected: " + correctSHA + "]", - URL: base.DocURL, + URL: setting.API.SwaggerURL, } var apiError context.APIError DecodeJSON(t, resp, &apiError) diff --git a/integrations/api_repo_file_update_test.go b/integrations/api_repo_file_update_test.go index 37438339bbd31..90fecf59d01a3 100644 --- a/integrations/api_repo_file_update_test.go +++ b/integrations/api_repo_file_update_test.go @@ -13,7 +13,6 @@ import ( "testing" "code.gitea.io/gitea/models" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/setting" @@ -136,8 +135,8 @@ func TestAPIUpdateFile(t *testing.T) { var fileResponse api.FileResponse DecodeJSON(t, resp, &fileResponse) expectedSHA := "08bd14b2e2852529157324de9c226b3364e76136" - expectedHTMLURL := fmt.Sprintf("http://localhost:"+setting.HTTPPort+"/user2/repo1/blob/new_branch/update/file%d.txt", fileID) - expectedDownloadURL := fmt.Sprintf("http://localhost:"+setting.HTTPPort+"/user2/repo1/raw/branch/new_branch/update/file%d.txt", fileID) + expectedHTMLURL := fmt.Sprintf(setting.AppURL+"user2/repo1/blob/new_branch/update/file%d.txt", fileID) + expectedDownloadURL := fmt.Sprintf(setting.AppURL+"user2/repo1/raw/branch/new_branch/update/file%d.txt", fileID) assert.EqualValues(t, expectedSHA, fileResponse.Content.SHA) assert.EqualValues(t, expectedHTMLURL, fileResponse.Content.HTMLURL) assert.EqualValues(t, expectedDownloadURL, fileResponse.Content.DownloadURL) @@ -155,8 +154,8 @@ func TestAPIUpdateFile(t *testing.T) { resp = session.MakeRequest(t, req, http.StatusOK) DecodeJSON(t, resp, &fileResponse) expectedSHA = "08bd14b2e2852529157324de9c226b3364e76136" - expectedHTMLURL = fmt.Sprintf("http://localhost:"+setting.HTTPPort+"/user2/repo1/blob/master/rename/update/file%d.txt", fileID) - expectedDownloadURL = fmt.Sprintf("http://localhost:"+setting.HTTPPort+"/user2/repo1/raw/branch/master/rename/update/file%d.txt", fileID) + expectedHTMLURL = fmt.Sprintf(setting.AppURL+"user2/repo1/blob/master/rename/update/file%d.txt", fileID) + expectedDownloadURL = fmt.Sprintf(setting.AppURL+"user2/repo1/raw/branch/master/rename/update/file%d.txt", fileID) assert.EqualValues(t, expectedSHA, fileResponse.Content.SHA) assert.EqualValues(t, expectedHTMLURL, fileResponse.Content.HTMLURL) assert.EqualValues(t, expectedDownloadURL, fileResponse.Content.DownloadURL) @@ -173,7 +172,7 @@ func TestAPIUpdateFile(t *testing.T) { resp = session.MakeRequest(t, req, http.StatusInternalServerError) expectedAPIError := context.APIError{ Message: "sha does not match [given: " + updateFileOptions.SHA + ", expected: " + correctSHA + "]", - URL: base.DocURL, + URL: setting.API.SwaggerURL, } var apiError context.APIError DecodeJSON(t, resp, &apiError) diff --git a/integrations/api_repo_git_tags_test.go b/integrations/api_repo_git_tags_test.go new file mode 100644 index 0000000000000..ae519249e03b0 --- /dev/null +++ b/integrations/api_repo_git_tags_test.go @@ -0,0 +1,59 @@ +// 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 integrations + +import ( + "net/http" + "testing" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/git" + api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/util" + + "github.com/stretchr/testify/assert" +) + +func TestAPIGitTags(t *testing.T) { + prepareTestEnv(t) + user := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User) + repo := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository) + // Login as User2. + session := loginUser(t, user.Name) + token := getTokenForLoggedInUser(t, session) + + // Set up git config for the tagger + git.NewCommand("config", "user.name", user.Name).RunInDir(repo.RepoPath()) + git.NewCommand("config", "user.email", user.Email).RunInDir(repo.RepoPath()) + + gitRepo, _ := git.OpenRepository(repo.RepoPath()) + commit, _ := gitRepo.GetBranchCommit("master") + lTagName := "lightweightTag" + gitRepo.CreateTag(lTagName, commit.ID.String()) + + aTagName := "annotatedTag" + aTagMessage := "my annotated message" + gitRepo.CreateAnnotatedTag(aTagName, aTagMessage, commit.ID.String()) + aTag, _ := gitRepo.GetTag(aTagName) + + // SHOULD work for annotated tags + req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/git/tags/%s?token=%s", user.Name, repo.Name, aTag.ID.String(), token) + res := session.MakeRequest(t, req, http.StatusOK) + + var tag *api.AnnotatedTag + DecodeJSON(t, res, &tag) + + assert.Equal(t, aTagName, tag.Tag) + assert.Equal(t, aTag.ID.String(), tag.SHA) + assert.Equal(t, commit.ID.String(), tag.Object.SHA) + assert.Equal(t, aTagMessage, tag.Message) + assert.Equal(t, user.Name, tag.Tagger.Name) + assert.Equal(t, user.Email, tag.Tagger.Email) + assert.Equal(t, util.URLJoin(repo.APIURL(), "git/tags", aTag.ID.String()), tag.URL) + + // Should NOT work for lightweight tags + badReq := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/git/tags/%s?token=%s", user.Name, repo.Name, commit.ID.String(), token) + session.MakeRequest(t, badReq, http.StatusBadRequest) +} diff --git a/integrations/api_repo_tags_test.go b/integrations/api_repo_tags_test.go index 13b446fb9637c..252037bd4a570 100644 --- a/integrations/api_repo_tags_test.go +++ b/integrations/api_repo_tags_test.go @@ -6,7 +6,6 @@ package integrations import ( "net/http" - "path" "testing" "code.gitea.io/gitea/models" @@ -32,7 +31,7 @@ func TestAPIReposGetTags(t *testing.T) { assert.EqualValues(t, 1, len(tags)) assert.Equal(t, "v1.1", tags[0].Name) assert.Equal(t, "65f1bf27bc3bf70f64657658635e66094edbcb4d", tags[0].Commit.SHA) - assert.Equal(t, path.Join(setting.AppSubURL, "/user2/repo1/commit/65f1bf27bc3bf70f64657658635e66094edbcb4d"), tags[0].Commit.URL) - assert.Equal(t, path.Join(setting.AppSubURL, "/user2/repo1/archive/v1.1.zip"), tags[0].ZipballURL) - assert.Equal(t, path.Join(setting.AppSubURL, "/user2/repo1/archive/v1.1.tar.gz"), tags[0].TarballURL) + assert.Equal(t, setting.AppURL+"api/v1/repos/user2/repo1/git/commits/65f1bf27bc3bf70f64657658635e66094edbcb4d", tags[0].Commit.URL) + assert.Equal(t, setting.AppURL+"user2/repo1/archive/v1.1.zip", tags[0].ZipballURL) + assert.Equal(t, setting.AppURL+"user2/repo1/archive/v1.1.tar.gz", tags[0].TarballURL) } diff --git a/integrations/branches_test.go b/integrations/branches_test.go index 01c6dd2a4b2af..e74f338aa2f3e 100644 --- a/integrations/branches_test.go +++ b/integrations/branches_test.go @@ -62,7 +62,7 @@ func branchAction(t *testing.T, button string) (*HTMLDoc, string) { req = NewRequestWithValues(t, "POST", link, map[string]string{ "_csrf": getCsrf(t, htmlDoc.doc), }) - resp = session.MakeRequest(t, req, http.StatusOK) + session.MakeRequest(t, req, http.StatusOK) url, err := url.Parse(link) assert.NoError(t, err) diff --git a/integrations/editor_test.go b/integrations/editor_test.go index 8e6effe7ebd8d..a46712293e86c 100644 --- a/integrations/editor_test.go +++ b/integrations/editor_test.go @@ -34,7 +34,7 @@ func TestCreateFile(t *testing.T) { "content": "Content", "commit_choice": "direct", }) - resp = session.MakeRequest(t, req, http.StatusFound) + session.MakeRequest(t, req, http.StatusFound) }) } @@ -48,7 +48,7 @@ func TestCreateFileOnProtectedBranch(t *testing.T) { "_csrf": csrf, "protected": "on", }) - resp := session.MakeRequest(t, req, http.StatusFound) + session.MakeRequest(t, req, http.StatusFound) // Check if master branch has been locked successfully flashCookie := session.GetCookie("macaron_flash") assert.NotNil(t, flashCookie) @@ -56,7 +56,7 @@ func TestCreateFileOnProtectedBranch(t *testing.T) { // Request editor page req = NewRequest(t, "GET", "/user2/repo1/_new/master/") - resp = session.MakeRequest(t, req, http.StatusOK) + resp := session.MakeRequest(t, req, http.StatusOK) doc := NewHTMLParser(t, resp.Body) lastCommit := doc.GetInputValueByName("last_commit") diff --git a/integrations/integration_test.go b/integrations/integration_test.go index 80a42efb5c2e7..e9b46ffcb9b9e 100644 --- a/integrations/integration_test.go +++ b/integrations/integration_test.go @@ -42,7 +42,7 @@ type NilResponseRecorder struct { } func (n *NilResponseRecorder) Write(b []byte) (int, error) { - n.Length = n.Length + len(b) + n.Length += len(b) return len(b), nil } @@ -141,8 +141,7 @@ func initIntegrationTest() { if err != nil { log.Fatalf("sql.Open: %v", err) } - rows, err := db.Query(fmt.Sprintf("SELECT 1 FROM pg_database WHERE datname = '%s'", - models.DbCfg.Name)) + rows, err := db.Query(fmt.Sprintf("SELECT 1 FROM pg_database WHERE datname = '%s'", models.DbCfg.Name)) if err != nil { log.Fatalf("db.Query: %v", err) } @@ -210,7 +209,7 @@ func (s *TestSession) MakeRequest(t testing.TB, req *http.Request, expectedStatu resp := MakeRequest(t, req, expectedStatus) ch := http.Header{} - ch.Add("Cookie", strings.Join(resp.HeaderMap["Set-Cookie"], ";")) + ch.Add("Cookie", strings.Join(resp.Header()["Set-Cookie"], ";")) cr := http.Request{Header: ch} s.jar.SetCookies(baseURL, cr.Cookies()) @@ -226,7 +225,7 @@ func (s *TestSession) MakeRequestNilResponseRecorder(t testing.TB, req *http.Req resp := MakeRequestNilResponseRecorder(t, req, expectedStatus) ch := http.Header{} - ch.Add("Cookie", strings.Join(resp.HeaderMap["Set-Cookie"], ";")) + ch.Add("Cookie", strings.Join(resp.Header()["Set-Cookie"], ";")) cr := http.Request{Header: ch} s.jar.SetCookies(baseURL, cr.Cookies()) @@ -266,7 +265,7 @@ func loginUserWithPassword(t testing.TB, userName, password string) *TestSession resp = MakeRequest(t, req, http.StatusFound) ch := http.Header{} - ch.Add("Cookie", strings.Join(resp.HeaderMap["Set-Cookie"], ";")) + ch.Add("Cookie", strings.Join(resp.Header()["Set-Cookie"], ";")) cr := http.Request{Header: ch} session := emptyTestSession(t) diff --git a/integrations/lfs_getobject_test.go b/integrations/lfs_getobject_test.go index 8f01d712a3d87..567cf13b45b6d 100644 --- a/integrations/lfs_getobject_test.go +++ b/integrations/lfs_getobject_test.go @@ -45,7 +45,7 @@ func storeObjectInRepo(t *testing.T, repositoryID int64, content *[]byte) string lfsMetaObject = &models.LFSMetaObject{Oid: oid, Size: int64(len(*content)), RepositoryID: repositoryID} } - lfsID = lfsID + 1 + lfsID++ lfsMetaObject, err = models.NewLFSMetaObject(lfsMetaObject) assert.NoError(t, err) contentStore := &lfs.ContentStore{BasePath: setting.LFS.ContentPath} diff --git a/integrations/migration-test/migration_test.go b/integrations/migration-test/migration_test.go index f168424865201..15b086c6e6229 100644 --- a/integrations/migration-test/migration_test.go +++ b/integrations/migration-test/migration_test.go @@ -57,21 +57,6 @@ func initMigrationTest(t *testing.T) { setting.NewLogServices(true) } -func getDialect() string { - dialect := "sqlite" - switch { - case setting.UseSQLite3: - dialect = "sqlite" - case setting.UseMySQL: - dialect = "mysql" - case setting.UsePostgreSQL: - dialect = "pgsql" - case setting.UseMSSQL: - dialect = "mssql" - } - return dialect -} - func availableVersions() ([]string, error) { migrationsDir, err := os.Open("integrations/migration-test") if err != nil { diff --git a/integrations/testlogger.go b/integrations/testlogger.go index c50daead9b4c2..43a1471f66040 100644 --- a/integrations/testlogger.go +++ b/integrations/testlogger.go @@ -73,7 +73,7 @@ func PrintCurrentTest(t testing.TB, skip ...int) { _, filename, line, _ := runtime.Caller(actualSkip) if log.CanColorStdout { - fmt.Fprintf(os.Stdout, "=== %s (%s:%d)\n", log.NewColoredValue(t.Name()), strings.TrimPrefix(filename, prefix), line) + fmt.Fprintf(os.Stdout, "=== %s (%s:%d)\n", fmt.Formatter(log.NewColoredValue(t.Name())), strings.TrimPrefix(filename, prefix), line) } else { fmt.Fprintf(os.Stdout, "=== %s (%s:%d)\n", t.Name(), strings.TrimPrefix(filename, prefix), line) } diff --git a/main.go b/main.go index d8c37fee2f097..30dbf2766224c 100644 --- a/main.go +++ b/main.go @@ -42,7 +42,7 @@ var ( func init() { setting.AppVer = Version - setting.AppBuiltWith = formatBuiltWith(Tags) + setting.AppBuiltWith = formatBuiltWith() // Grab the original help templates originalAppHelpTemplate = cli.AppHelpTemplate @@ -56,7 +56,7 @@ func main() { app.Usage = "A painless self-hosted Git service" app.Description = `By default, gitea will start serving using the webserver with no arguments - which can alternatively be run by running the subcommand web.` - app.Version = Version + formatBuiltWith(Tags) + app.Version = Version + formatBuiltWith() app.Commands = []cli.Command{ cmd.CmdWeb, cmd.CmdServ, @@ -67,6 +67,7 @@ arguments - which can alternatively be run by running the subcommand web.` cmd.CmdGenerate, cmd.CmdMigrate, cmd.CmdKeys, + cmd.CmdConvert, } // Now adjust these commands to add our global configuration options @@ -178,7 +179,7 @@ DEFAULT CONFIGURATION: `, originalTemplate, setting.CustomPath, overrided, setting.CustomConf, setting.AppPath, setting.AppWorkPath) } -func formatBuiltWith(makeTags string) string { +func formatBuiltWith() string { var version = runtime.Version() if len(MakeVersion) > 0 { version = MakeVersion + ", " + runtime.Version() diff --git a/models/access_test.go b/models/access_test.go index d6a1c92b90202..db6f655a670dc 100644 --- a/models/access_test.go +++ b/models/access_test.go @@ -10,13 +10,6 @@ import ( "github.com/stretchr/testify/assert" ) -var accessModes = []AccessMode{ - AccessModeRead, - AccessModeWrite, - AccessModeAdmin, - AccessModeOwner, -} - func TestAccessLevel(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) diff --git a/models/branches.go b/models/branches.go index 1730c752bafb3..fa4215d6a03a7 100644 --- a/models/branches.go +++ b/models/branches.go @@ -128,14 +128,14 @@ func (protectBranch *ProtectedBranch) GetGrantedApprovalsCount(pr *PullRequest) } // GetProtectedBranchByRepoID getting protected branch by repo ID -func GetProtectedBranchByRepoID(RepoID int64) ([]*ProtectedBranch, error) { +func GetProtectedBranchByRepoID(repoID int64) ([]*ProtectedBranch, error) { protectedBranches := make([]*ProtectedBranch, 0) - return protectedBranches, x.Where("repo_id = ?", RepoID).Desc("updated_unix").Find(&protectedBranches) + return protectedBranches, x.Where("repo_id = ?", repoID).Desc("updated_unix").Find(&protectedBranches) } // GetProtectedBranchBy getting protected branch by ID/Name -func GetProtectedBranchBy(repoID int64, BranchName string) (*ProtectedBranch, error) { - rel := &ProtectedBranch{RepoID: repoID, BranchName: BranchName} +func GetProtectedBranchBy(repoID int64, branchName string) (*ProtectedBranch, error) { + rel := &ProtectedBranch{RepoID: repoID, BranchName: branchName} has, err := x.Get(rel) if err != nil { return nil, err diff --git a/models/convert.go b/models/convert.go new file mode 100644 index 0000000000000..c34be973c6b53 --- /dev/null +++ b/models/convert.go @@ -0,0 +1,27 @@ +// Copyright 2019 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 models + +import "fmt" + +// ConvertUtf8ToUtf8mb4 converts database and tables from utf8 to utf8mb4 if it's mysql +func ConvertUtf8ToUtf8mb4() error { + _, err := x.Exec(fmt.Sprintf("ALTER DATABASE `%s` CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci", DbCfg.Name)) + if err != nil { + return err + } + + tables, err := x.DBMetas() + if err != nil { + return err + } + for _, table := range tables { + if _, err := x.Exec(fmt.Sprintf("ALTER TABLE `%s` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;", table.Name)); err != nil { + return err + } + } + + return nil +} diff --git a/models/error.go b/models/error.go index fe0f05d36b27c..11ca6e6863f77 100644 --- a/models/error.go +++ b/models/error.go @@ -674,6 +674,23 @@ func (err ErrRepoAlreadyExist) Error() string { return fmt.Sprintf("repository already exists [uname: %s, name: %s]", err.Uname, err.Name) } +// ErrForkAlreadyExist represents a "ForkAlreadyExist" kind of error. +type ErrForkAlreadyExist struct { + Uname string + RepoName string + ForkName string +} + +// IsErrForkAlreadyExist checks if an error is an ErrForkAlreadyExist. +func IsErrForkAlreadyExist(err error) bool { + _, ok := err.(ErrForkAlreadyExist) + return ok +} + +func (err ErrForkAlreadyExist) Error() string { + return fmt.Sprintf("repository is already forked by user [uname: %s, repo path: %s, fork path: %s]", err.Uname, err.RepoName, err.ForkName) +} + // ErrRepoRedirectNotExist represents a "RepoRedirectNotExist" kind of error. type ErrRepoRedirectNotExist struct { OwnerID int64 diff --git a/models/fixtures/milestone.yml b/models/fixtures/milestone.yml index 8192c4fbe1b09..15f422fc3b5c2 100644 --- a/models/fixtures/milestone.yml +++ b/models/fixtures/milestone.yml @@ -13,3 +13,11 @@ content: content2 is_closed: false num_issues: 0 + +- + id: 3 + repo_id: 1 + name: milestone3 + content: content3 + is_closed: true + num_issues: 0 diff --git a/models/fixtures/repository.yml b/models/fixtures/repository.yml index 083182e2bcc13..609f421a9033d 100644 --- a/models/fixtures/repository.yml +++ b/models/fixtures/repository.yml @@ -8,7 +8,8 @@ num_closed_issues: 1 num_pulls: 2 num_closed_pulls: 0 - num_milestones: 2 + num_milestones: 3 + num_closed_milestones: 1 num_watches: 3 - @@ -495,4 +496,4 @@ num_stars: 0 num_forks: 0 num_issues: 0 - is_mirror: false \ No newline at end of file + is_mirror: false diff --git a/models/git_blame.go b/models/git_blame.go index 7b4fb64a7081c..2b439a23b9d82 100644 --- a/models/git_blame.go +++ b/models/git_blame.go @@ -40,7 +40,7 @@ func (r *BlameReader) NextPart() (*BlamePart, error) { scanner := r.scanner if r.lastSha != nil { - blamePart = &BlamePart{*r.lastSha, make([]string, 0, 0)} + blamePart = &BlamePart{*r.lastSha, make([]string, 0)} } for scanner.Scan() { @@ -56,7 +56,7 @@ func (r *BlameReader) NextPart() (*BlamePart, error) { sha1 := lines[1] if blamePart == nil { - blamePart = &BlamePart{sha1, make([]string, 0, 0)} + blamePart = &BlamePart{sha1, make([]string, 0)} } if blamePart.Sha != sha1 { diff --git a/models/git_diff.go b/models/git_diff.go index ac2a5f90d74e8..a6ea7306d491f 100644 --- a/models/git_diff.go +++ b/models/git_diff.go @@ -384,13 +384,9 @@ func CutDiffAroundLine(originalDiff io.Reader, line int64, old bool, numbersOfLi // headers + hunk header newHunk := make([]string, headerLines) // transfer existing headers - for idx, lof := range hunk[:headerLines] { - newHunk[idx] = lof - } + copy(newHunk, hunk[:headerLines]) // transfer last n lines - for _, lof := range hunk[len(hunk)-numbersOfLine-1:] { - newHunk = append(newHunk, lof) - } + newHunk = append(newHunk, hunk[len(hunk)-numbersOfLine-1:]...) // calculate newBegin, ... by counting lines for i := len(hunk) - 1; i >= len(hunk)-numbersOfLine; i-- { switch hunk[i][0] { @@ -582,7 +578,10 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D diff.Files = append(diff.Files, curFile) if len(diff.Files) >= maxFiles { diff.IsIncomplete = true - io.Copy(ioutil.Discard, reader) + _, err := io.Copy(ioutil.Discard, reader) + if err != nil { + return nil, fmt.Errorf("Copy: %v", err) + } break } curFileLinesCount = 0 diff --git a/models/git_diff_test.go b/models/git_diff_test.go index 2111e9044f994..deca7c8d4affa 100644 --- a/models/git_diff_test.go +++ b/models/git_diff_test.go @@ -17,12 +17,6 @@ func assertEqual(t *testing.T, s1 string, s2 template.HTML) { } } -func assertLineEqual(t *testing.T, d1 *DiffLine, d2 *DiffLine) { - if d1 != d2 { - t.Errorf("%v should be equal %v", d1, d2) - } -} - func TestDiffToHTML(t *testing.T) { assertEqual(t, "+foo bar biz", diffToHTML([]dmp.Diff{ {Type: dmp.DiffEqual, Text: "foo "}, diff --git a/models/issue.go b/models/issue.go index 999bd2f7a9b4d..27298b8a86d2f 100644 --- a/models/issue.go +++ b/models/issue.go @@ -1330,7 +1330,7 @@ func sortIssuesSession(sess *xorm.Session, sortType string) { } } -func (opts *IssuesOptions) setupSession(sess *xorm.Session) error { +func (opts *IssuesOptions) setupSession(sess *xorm.Session) { if opts.Page >= 0 && opts.PageSize > 0 { var start int if opts.Page == 0 { @@ -1389,7 +1389,6 @@ func (opts *IssuesOptions) setupSession(sess *xorm.Session) error { fmt.Sprintf("issue.id = il%[1]d.issue_id AND il%[1]d.label_id = %[2]d", i, labelID)) } } - return nil } // CountIssuesByRepo map from repoID to number of issues matching the options @@ -1397,9 +1396,7 @@ func CountIssuesByRepo(opts *IssuesOptions) (map[int64]int64, error) { sess := x.NewSession() defer sess.Close() - if err := opts.setupSession(sess); err != nil { - return nil, err - } + opts.setupSession(sess) countsSlice := make([]*struct { RepoID int64 @@ -1424,9 +1421,7 @@ func Issues(opts *IssuesOptions) ([]*Issue, error) { sess := x.NewSession() defer sess.Close() - if err := opts.setupSession(sess); err != nil { - return nil, err - } + opts.setupSession(sess) sortIssuesSession(sess, opts.SortType) issues := make([]*Issue, 0, setting.UI.IssuePagingNum) diff --git a/models/issue_comment.go b/models/issue_comment.go index 60fb5b0420e56..d75d9d7db1f6e 100644 --- a/models/issue_comment.go +++ b/models/issue_comment.go @@ -171,17 +171,6 @@ func (c *Comment) loadPoster(e Engine) (err error) { return err } -func (c *Comment) loadAttachments(e Engine) (err error) { - if len(c.Attachments) > 0 { - return - } - c.Attachments, err = getAttachmentsByCommentID(e, c.ID) - if err != nil { - log.Error("getAttachmentsByCommentID[%d]: %v", c.ID, err) - } - return err -} - // AfterDelete is invoked from XORM after the object is deleted. func (c *Comment) AfterDelete() { if c.ID <= 0 { @@ -403,16 +392,23 @@ func (c *Comment) mailParticipants(e Engine, opType ActionType, issue *Issue) (e return fmt.Errorf("UpdateIssueMentions [%d]: %v", c.IssueID, err) } - content := c.Content + if len(c.Content) > 0 { + if err = mailIssueCommentToParticipants(e, issue, c.Poster, c.Content, c, mentions); err != nil { + log.Error("mailIssueCommentToParticipants: %v", err) + } + } switch opType { case ActionCloseIssue: - content = fmt.Sprintf("Closed #%d", issue.Index) + ct := fmt.Sprintf("Closed #%d.", issue.Index) + if err = mailIssueCommentToParticipants(e, issue, c.Poster, ct, c, mentions); err != nil { + log.Error("mailIssueCommentToParticipants: %v", err) + } case ActionReopenIssue: - content = fmt.Sprintf("Reopened #%d", issue.Index) - } - if err = mailIssueCommentToParticipants(e, issue, c.Poster, content, c, mentions); err != nil { - log.Error("mailIssueCommentToParticipants: %v", err) + ct := fmt.Sprintf("Reopened #%d.", issue.Index) + if err = mailIssueCommentToParticipants(e, issue, c.Poster, ct, c, mentions); err != nil { + log.Error("mailIssueCommentToParticipants: %v", err) + } } return nil @@ -456,7 +452,7 @@ func (c *Comment) LoadReview() error { return c.loadReview(x) } -func (c *Comment) checkInvalidation(e Engine, doer *User, repo *git.Repository, branch string) error { +func (c *Comment) checkInvalidation(doer *User, repo *git.Repository, branch string) error { // FIXME differentiate between previous and proposed line commit, err := repo.LineBlame(branch, repo.Path, c.TreePath, uint(c.UnsignedLine())) if err != nil { @@ -472,7 +468,7 @@ func (c *Comment) checkInvalidation(e Engine, doer *User, repo *git.Repository, // CheckInvalidation checks if the line of code comment got changed by another commit. // If the line got changed the comment is going to be invalidated. func (c *Comment) CheckInvalidation(repo *git.Repository, doer *User, branch string) error { - return c.checkInvalidation(x, doer, repo, branch) + return c.checkInvalidation(doer, repo, branch) } // DiffSide returns "previous" if Comment.Line is a LOC of the previous changes and "proposed" if it is a LOC of the proposed changes. @@ -908,7 +904,7 @@ func CreateCodeComment(doer *User, repo *Repository, issue *Issue, content, tree commit, err := gitRepo.LineBlame(pr.GetGitRefName(), gitRepo.Path, treePath, uint(line)) if err == nil { commitID = commit.ID.String() - } else if err != nil && !strings.Contains(err.Error(), "exit status 128 - fatal: no such path") { + } else if !strings.Contains(err.Error(), "exit status 128 - fatal: no such path") { return nil, fmt.Errorf("LineBlame[%s, %s, %s, %d]: %v", pr.GetGitRefName(), gitRepo.Path, treePath, line, err) } } diff --git a/models/issue_comment_list.go b/models/issue_comment_list.go index a8c8123280c7f..ae2a89a01ac77 100644 --- a/models/issue_comment_list.go +++ b/models/issue_comment_list.go @@ -36,7 +36,7 @@ func (comments CommentList) loadPosters(e Engine) error { if err != nil { return err } - left = left - limit + left -= limit posterIDs = posterIDs[limit:] } @@ -94,13 +94,13 @@ func (comments CommentList) loadLabels(e Engine) error { var label Label err = rows.Scan(&label) if err != nil { - rows.Close() + _ = rows.Close() return err } commentLabels[label.ID] = &label } - rows.Close() - left = left - limit + _ = rows.Close() + left -= limit labelIDs = labelIDs[limit:] } @@ -143,7 +143,7 @@ func (comments CommentList) loadMilestones(e Engine) error { if err != nil { return err } - left = left - limit + left -= limit milestoneIDs = milestoneIDs[limit:] } @@ -186,7 +186,7 @@ func (comments CommentList) loadOldMilestones(e Engine) error { if err != nil { return err } - left = left - limit + left -= limit milestoneIDs = milestoneIDs[limit:] } @@ -236,9 +236,9 @@ func (comments CommentList) loadAssignees(e Engine) error { assignees[user.ID] = &user } - rows.Close() + _ = rows.Close() - left = left - limit + left -= limit assigneeIDs = assigneeIDs[limit:] } @@ -310,9 +310,9 @@ func (comments CommentList) loadIssues(e Engine) error { issues[issue.ID] = &issue } - rows.Close() + _ = rows.Close() - left = left - limit + left -= limit issueIDs = issueIDs[limit:] } @@ -361,15 +361,15 @@ func (comments CommentList) loadDependentIssues(e Engine) error { var issue Issue err = rows.Scan(&issue) if err != nil { - rows.Close() + _ = rows.Close() return err } issues[issue.ID] = &issue } - rows.Close() + _ = rows.Close() - left = left - limit + left -= limit issueIDs = issueIDs[limit:] } @@ -406,14 +406,14 @@ func (comments CommentList) loadAttachments(e Engine) (err error) { var attachment Attachment err = rows.Scan(&attachment) if err != nil { - rows.Close() + _ = rows.Close() return err } attachments[attachment.CommentID] = append(attachments[attachment.CommentID], &attachment) } - rows.Close() - left = left - limit + _ = rows.Close() + left -= limit commentsIDs = commentsIDs[limit:] } @@ -457,15 +457,15 @@ func (comments CommentList) loadReviews(e Engine) error { var review Review err = rows.Scan(&review) if err != nil { - rows.Close() + _ = rows.Close() return err } reviews[review.ID] = &review } - rows.Close() + _ = rows.Close() - left = left - limit + left -= limit reviewIDs = reviewIDs[limit:] } diff --git a/models/issue_label.go b/models/issue_label.go index 38266f3e7c9dd..363d4bb814f46 100644 --- a/models/issue_label.go +++ b/models/issue_label.go @@ -401,14 +401,6 @@ func NewIssueLabels(issue *Issue, labels []*Label, doer *User) (err error) { return sess.Commit() } -func getIssueLabels(e Engine, issueID int64) ([]*IssueLabel, error) { - issueLabels := make([]*IssueLabel, 0, 10) - return issueLabels, e. - Where("issue_id=?", issueID). - Asc("label_id"). - Find(&issueLabels) -} - func deleteIssueLabel(e *xorm.Session, issue *Issue, label *Label, doer *User) (err error) { if count, err := e.Delete(&IssueLabel{ IssueID: issue.ID, diff --git a/models/issue_list.go b/models/issue_list.go index a1aab488fcb91..4ddb32da1311d 100644 --- a/models/issue_list.go +++ b/models/issue_list.go @@ -7,6 +7,8 @@ package models import ( "fmt" + "code.gitea.io/gitea/modules/log" + "github.com/go-xorm/builder" ) @@ -47,7 +49,7 @@ func (issues IssueList) loadRepositories(e Engine) ([]*Repository, error) { if err != nil { return nil, fmt.Errorf("find repository: %v", err) } - left = left - limit + left -= limit repoIDs = repoIDs[limit:] } @@ -91,7 +93,7 @@ func (issues IssueList) loadPosters(e Engine) error { if err != nil { return err } - left = left - limit + left -= limit posterIDs = posterIDs[limit:] } @@ -146,13 +148,21 @@ func (issues IssueList) loadLabels(e Engine) error { var labelIssue LabelIssue err = rows.Scan(&labelIssue) if err != nil { - rows.Close() + // When there are no rows left and we try to close it, xorm will complain with an error. + // Since that is not relevant for us, we can safely ignore it. + if err := rows.Close(); err != nil { + log.Error("IssueList.loadLabels: Close: %v", err) + } return err } issueLabels[labelIssue.IssueLabel.IssueID] = append(issueLabels[labelIssue.IssueLabel.IssueID], labelIssue.Label) } - rows.Close() - left = left - limit + // When there are no rows left and we try to close it, xorm will complain with an error. + // Since that is not relevant for us, we can safely ignore it. + if err := rows.Close(); err != nil { + log.Error("IssueList.loadLabels: Close: %v", err) + } + left -= limit issueIDs = issueIDs[limit:] } @@ -191,7 +201,7 @@ func (issues IssueList) loadMilestones(e Engine) error { if err != nil { return err } - left = left - limit + left -= limit milestoneIDs = milestoneIDs[limit:] } @@ -231,15 +241,22 @@ func (issues IssueList) loadAssignees(e Engine) error { var assigneeIssue AssigneeIssue err = rows.Scan(&assigneeIssue) if err != nil { - rows.Close() + // When there are no rows left and we try to close it, xorm will complain with an error. + // Since that is not relevant for us, we can safely ignore it. + if err := rows.Close(); err != nil { + log.Error("IssueList.loadAssignees: Close: %v", err) + } return err } assignees[assigneeIssue.IssueAssignee.IssueID] = append(assignees[assigneeIssue.IssueAssignee.IssueID], assigneeIssue.Assignee) } - rows.Close() - - left = left - limit + // When there are no rows left and we try to close it, xorm will complain with an error. + // Since that is not relevant for us, we can safely ignore it. + if err := rows.Close(); err != nil { + log.Error("IssueList.loadAssignees: Close: %v", err) + } + left -= limit issueIDs = issueIDs[limit:] } @@ -283,14 +300,21 @@ func (issues IssueList) loadPullRequests(e Engine) error { var pr PullRequest err = rows.Scan(&pr) if err != nil { - rows.Close() + // When there are no rows left and we try to close it, xorm will complain with an error. + // Since that is not relevant for us, we can safely ignore it. + if err := rows.Close(); err != nil { + log.Error("IssueList.loadPullRequests: Close: %v", err) + } return err } pullRequestMaps[pr.IssueID] = &pr } - - rows.Close() - left = left - limit + // When there are no rows left and we try to close it, xorm will complain with an error. + // Since that is not relevant for us, we can safely ignore it. + if err := rows.Close(); err != nil { + log.Error("IssueList.loadPullRequests: Close: %v", err) + } + left -= limit issuesIDs = issuesIDs[limit:] } @@ -325,14 +349,21 @@ func (issues IssueList) loadAttachments(e Engine) (err error) { var attachment Attachment err = rows.Scan(&attachment) if err != nil { - rows.Close() + // When there are no rows left and we try to close it, xorm will complain with an error. + // Since that is not relevant for us, we can safely ignore it. + if err := rows.Close(); err != nil { + log.Error("IssueList.loadAttachments: Close: %v", err) + } return err } attachments[attachment.IssueID] = append(attachments[attachment.IssueID], &attachment) } - - rows.Close() - left = left - limit + // When there are no rows left and we try to close it, xorm will complain with an error. + // Since that is not relevant for us, we can safely ignore it. + if err := rows.Close(); err != nil { + log.Error("IssueList.loadAttachments: Close: %v", err) + } + left -= limit issuesIDs = issuesIDs[limit:] } @@ -368,13 +399,21 @@ func (issues IssueList) loadComments(e Engine, cond builder.Cond) (err error) { var comment Comment err = rows.Scan(&comment) if err != nil { - rows.Close() + // When there are no rows left and we try to close it, xorm will complain with an error. + // Since that is not relevant for us, we can safely ignore it. + if err := rows.Close(); err != nil { + log.Error("IssueList.loadComments: Close: %v", err) + } return err } comments[comment.IssueID] = append(comments[comment.IssueID], &comment) } - rows.Close() - left = left - limit + // When there are no rows left and we try to close it, xorm will complain with an error. + // Since that is not relevant for us, we can safely ignore it. + if err := rows.Close(); err != nil { + log.Error("IssueList.loadComments: Close: %v", err) + } + left -= limit issuesIDs = issuesIDs[limit:] } @@ -422,13 +461,21 @@ func (issues IssueList) loadTotalTrackedTimes(e Engine) (err error) { var totalTime totalTimesByIssue err = rows.Scan(&totalTime) if err != nil { - rows.Close() + // When there are no rows left and we try to close it, xorm will complain with an error. + // Since that is not relevant for us, we can safely ignore it. + if err := rows.Close(); err != nil { + log.Error("IssueList.loadTotalTrackedTimes: Close: %v", err) + } return err } trackedTimes[totalTime.IssueID] = totalTime.Time } - rows.Close() - left = left - limit + // When there are no rows left and we try to close it, xorm will complain with an error. + // Since that is not relevant for us, we can safely ignore it. + if err := rows.Close(); err != nil { + log.Error("IssueList.loadTotalTrackedTimes: Close: %v", err) + } + left -= limit ids = ids[limit:] } @@ -439,33 +486,33 @@ func (issues IssueList) loadTotalTrackedTimes(e Engine) (err error) { } // loadAttributes loads all attributes, expect for attachments and comments -func (issues IssueList) loadAttributes(e Engine) (err error) { - if _, err = issues.loadRepositories(e); err != nil { - return +func (issues IssueList) loadAttributes(e Engine) error { + if _, err := issues.loadRepositories(e); err != nil { + return fmt.Errorf("issue.loadAttributes: loadRepositories: %v", err) } - if err = issues.loadPosters(e); err != nil { - return + if err := issues.loadPosters(e); err != nil { + return fmt.Errorf("issue.loadAttributes: loadPosters: %v", err) } - if err = issues.loadLabels(e); err != nil { - return + if err := issues.loadLabels(e); err != nil { + return fmt.Errorf("issue.loadAttributes: loadLabels: %v", err) } - if err = issues.loadMilestones(e); err != nil { - return + if err := issues.loadMilestones(e); err != nil { + return fmt.Errorf("issue.loadAttributes: loadMilestones: %v", err) } - if err = issues.loadAssignees(e); err != nil { - return + if err := issues.loadAssignees(e); err != nil { + return fmt.Errorf("issue.loadAttributes: loadAssignees: %v", err) } - if err = issues.loadPullRequests(e); err != nil { - return + if err := issues.loadPullRequests(e); err != nil { + return fmt.Errorf("issue.loadAttributes: loadPullRequests: %v", err) } - if err = issues.loadTotalTrackedTimes(e); err != nil { - return + if err := issues.loadTotalTrackedTimes(e); err != nil { + return fmt.Errorf("issue.loadAttributes: loadTotalTrackedTimes: %v", err) } return nil diff --git a/models/issue_mail.go b/models/issue_mail.go index 16f85ba37821f..01a12b16d2a8e 100644 --- a/models/issue_mail.go +++ b/models/issue_mail.go @@ -118,26 +118,41 @@ func mailIssueCommentToParticipants(e Engine, issue *Issue, doer *User, content // MailParticipants sends new issue thread created emails to repository watchers // and mentioned people. -func (issue *Issue) MailParticipants(opType ActionType) (err error) { - return issue.mailParticipants(x, opType) +func (issue *Issue) MailParticipants(doer *User, opType ActionType) (err error) { + return issue.mailParticipants(x, doer, opType) } -func (issue *Issue) mailParticipants(e Engine, opType ActionType) (err error) { +func (issue *Issue) mailParticipants(e Engine, doer *User, opType ActionType) (err error) { mentions := markup.FindAllMentions(issue.Content) + if err = UpdateIssueMentions(e, issue.ID, mentions); err != nil { return fmt.Errorf("UpdateIssueMentions [%d]: %v", issue.ID, err) } - var content = issue.Content + if len(issue.Content) > 0 { + if err = mailIssueCommentToParticipants(e, issue, doer, issue.Content, nil, mentions); err != nil { + log.Error("mailIssueCommentToParticipants: %v", err) + } + } + switch opType { + case ActionCreateIssue, ActionCreatePullRequest: + if len(issue.Content) == 0 { + ct := fmt.Sprintf("Created #%d.", issue.Index) + if err = mailIssueCommentToParticipants(e, issue, doer, ct, nil, mentions); err != nil { + log.Error("mailIssueCommentToParticipants: %v", err) + } + } case ActionCloseIssue, ActionClosePullRequest: - content = fmt.Sprintf("Closed #%d", issue.Index) + ct := fmt.Sprintf("Closed #%d.", issue.Index) + if err = mailIssueCommentToParticipants(e, issue, doer, ct, nil, mentions); err != nil { + log.Error("mailIssueCommentToParticipants: %v", err) + } case ActionReopenIssue, ActionReopenPullRequest: - content = fmt.Sprintf("Reopened #%d", issue.Index) - } - - if err = mailIssueCommentToParticipants(e, issue, issue.Poster, content, nil, mentions); err != nil { - log.Error("mailIssueCommentToParticipants: %v", err) + ct := fmt.Sprintf("Reopened #%d.", issue.Index) + if err = mailIssueCommentToParticipants(e, issue, doer, ct, nil, mentions); err != nil { + log.Error("mailIssueCommentToParticipants: %v", err) + } } return nil diff --git a/models/issue_milestone.go b/models/issue_milestone.go index 3bde4b558cf65..f279dda195e7d 100644 --- a/models/issue_milestone.go +++ b/models/issue_milestone.go @@ -190,10 +190,26 @@ func (milestones MilestoneList) getMilestoneIDs() []int64 { } // GetMilestonesByRepoID returns all opened milestones of a repository. -func GetMilestonesByRepoID(repoID int64) (MilestoneList, error) { +func GetMilestonesByRepoID(repoID int64, state api.StateType) (MilestoneList, error) { + + sess := x.Where("repo_id = ?", repoID) + + switch state { + case api.StateClosed: + sess = sess.And("is_closed = ?", true) + + case api.StateAll: + break + + case api.StateOpen: + fallthrough + + default: + sess = sess.And("is_closed = ?", false) + } + miles := make([]*Milestone, 0, 10) - return miles, x.Where("repo_id = ? AND is_closed = ?", repoID, false). - Asc("deadline_unix").Asc("id").Find(&miles) + return miles, sess.Asc("deadline_unix").Asc("id").Find(&miles) } // GetMilestones returns a list of milestones of given repository and status. diff --git a/models/issue_milestone_test.go b/models/issue_milestone_test.go index fb1ee8b7a5c89..f9e51aff318ee 100644 --- a/models/issue_milestone_test.go +++ b/models/issue_milestone_test.go @@ -69,20 +69,43 @@ func TestGetMilestoneByRepoID(t *testing.T) { func TestGetMilestonesByRepoID(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) - test := func(repoID int64) { + test := func(repoID int64, state api.StateType) { repo := AssertExistsAndLoadBean(t, &Repository{ID: repoID}).(*Repository) - milestones, err := GetMilestonesByRepoID(repo.ID) + milestones, err := GetMilestonesByRepoID(repo.ID, state) assert.NoError(t, err) - assert.Len(t, milestones, repo.NumMilestones) + + var n int + + switch state { + case api.StateClosed: + n = repo.NumClosedMilestones + + case api.StateAll: + n = repo.NumMilestones + + case api.StateOpen: + fallthrough + + default: + n = repo.NumOpenMilestones + } + + assert.Len(t, milestones, n) for _, milestone := range milestones { assert.EqualValues(t, repoID, milestone.RepoID) } } - test(1) - test(2) - test(3) - - milestones, err := GetMilestonesByRepoID(NonexistentID) + test(1, api.StateOpen) + test(1, api.StateAll) + test(1, api.StateClosed) + test(2, api.StateOpen) + test(2, api.StateAll) + test(2, api.StateClosed) + test(3, api.StateOpen) + test(3, api.StateClosed) + test(3, api.StateAll) + + milestones, err := GetMilestonesByRepoID(NonexistentID, api.StateOpen) assert.NoError(t, err) assert.Len(t, milestones, 0) } diff --git a/models/log.go b/models/log.go index 4994545c5f429..38d6caf07c979 100644 --- a/models/log.go +++ b/models/log.go @@ -15,7 +15,6 @@ import ( // XORMLogBridge a logger bridge from Logger to xorm type XORMLogBridge struct { showSQL bool - level core.LogLevel logger *log.Logger } @@ -34,42 +33,42 @@ func (l *XORMLogBridge) Log(skip int, level log.Level, format string, v ...inter // Debug show debug log func (l *XORMLogBridge) Debug(v ...interface{}) { - l.Log(2, log.DEBUG, fmt.Sprint(v...)) + _ = l.Log(2, log.DEBUG, fmt.Sprint(v...)) } // Debugf show debug log func (l *XORMLogBridge) Debugf(format string, v ...interface{}) { - l.Log(2, log.DEBUG, format, v...) + _ = l.Log(2, log.DEBUG, format, v...) } // Error show error log func (l *XORMLogBridge) Error(v ...interface{}) { - l.Log(2, log.ERROR, fmt.Sprint(v...)) + _ = l.Log(2, log.ERROR, fmt.Sprint(v...)) } // Errorf show error log func (l *XORMLogBridge) Errorf(format string, v ...interface{}) { - l.Log(2, log.ERROR, format, v...) + _ = l.Log(2, log.ERROR, format, v...) } // Info show information level log func (l *XORMLogBridge) Info(v ...interface{}) { - l.Log(2, log.INFO, fmt.Sprint(v...)) + _ = l.Log(2, log.INFO, fmt.Sprint(v...)) } // Infof show information level log func (l *XORMLogBridge) Infof(format string, v ...interface{}) { - l.Log(2, log.INFO, format, v...) + _ = l.Log(2, log.INFO, format, v...) } // Warn show warning log func (l *XORMLogBridge) Warn(v ...interface{}) { - l.Log(2, log.WARN, fmt.Sprint(v...)) + _ = l.Log(2, log.WARN, fmt.Sprint(v...)) } // Warnf show warnning log func (l *XORMLogBridge) Warnf(format string, v ...interface{}) { - l.Log(2, log.WARN, format, v...) + _ = l.Log(2, log.WARN, format, v...) } // Level get logger level diff --git a/models/login_source.go b/models/login_source.go index 9b8173b84dfb5..8eefec4ae5873 100644 --- a/models/login_source.go +++ b/models/login_source.go @@ -164,8 +164,7 @@ func Cell2Int64(val xorm.Cell) int64 { // BeforeSet is invoked from XORM before setting the value of a field of this object. func (source *LoginSource) BeforeSet(colName string, val xorm.Cell) { - switch colName { - case "type": + if colName == "type" { switch LoginType(Cell2Int64(val)) { case LoginLDAP, LoginDLDAP: source.Cfg = new(LDAPConfig) @@ -282,10 +281,12 @@ func CreateLoginSource(source *LoginSource) error { oAuth2Config := source.OAuth2() err = oauth2.RegisterProvider(source.Name, oAuth2Config.Provider, oAuth2Config.ClientID, oAuth2Config.ClientSecret, oAuth2Config.OpenIDConnectAutoDiscoveryURL, oAuth2Config.CustomURLMapping) err = wrapOpenIDConnectInitializeError(err, source.Name, oAuth2Config) - if err != nil { // remove the LoginSource in case of errors while registering OAuth2 providers - x.Delete(source) + if _, err := x.Delete(source); err != nil { + log.Error("CreateLoginSource: Error while wrapOpenIDConnectInitializeError: %v", err) + } + return err } } return err @@ -325,10 +326,12 @@ func UpdateSource(source *LoginSource) error { oAuth2Config := source.OAuth2() err = oauth2.RegisterProvider(source.Name, oAuth2Config.Provider, oAuth2Config.ClientID, oAuth2Config.ClientSecret, oAuth2Config.OpenIDConnectAutoDiscoveryURL, oAuth2Config.CustomURLMapping) err = wrapOpenIDConnectInitializeError(err, source.Name, oAuth2Config) - if err != nil { // restore original values since we cannot update the provider it self - x.ID(source.ID).AllCols().Update(originalLoginSource) + if _, err := x.ID(source.ID).AllCols().Update(originalLoginSource); err != nil { + log.Error("UpdateSource: Error while wrapOpenIDConnectInitializeError: %v", err) + } + return err } } return err @@ -385,7 +388,7 @@ func composeFullName(firstname, surname, username string) string { } var ( - alphaDashDotPattern = regexp.MustCompile("[^\\w-\\.]") + alphaDashDotPattern = regexp.MustCompile(`[^\w-\.]`) ) // LoginViaLDAP queries if login/password is valid against the LDAP directory pool, @@ -401,7 +404,7 @@ func LoginViaLDAP(user *User, login, password string, source *LoginSource, autoR if !autoRegister { if isAttributeSSHPublicKeySet && synchronizeLdapSSHPublicKeys(user, source, sr.SSHPublicKey) { - RewriteAllPublicKeys() + return user, RewriteAllPublicKeys() } return user, nil @@ -435,7 +438,7 @@ func LoginViaLDAP(user *User, login, password string, source *LoginSource, autoR err := CreateUser(user) if err == nil && isAttributeSSHPublicKeySet && addLdapSSHPublicKeys(user, source, sr.SSHPublicKey) { - RewriteAllPublicKeys() + err = RewriteAllPublicKeys() } return user, err diff --git a/models/mail.go b/models/mail.go index 6be0df95ba51c..2bb07607a4119 100644 --- a/models/mail.go +++ b/models/mail.go @@ -157,10 +157,13 @@ func composeTplData(subject, body, link string) map[string]interface{} { func composeIssueCommentMessage(issue *Issue, doer *User, content string, comment *Comment, tplName base.TplName, tos []string, info string) *mailer.Message { subject := issue.mailSubject() - issue.LoadRepo() + err := issue.LoadRepo() + if err != nil { + log.Error("LoadRepo: %v", err) + } body := string(markup.RenderByType(markdown.MarkupName, []byte(content), issue.Repo.HTMLURL(), issue.Repo.ComposeMetas())) - data := make(map[string]interface{}, 10) + var data = make(map[string]interface{}, 10) if comment != nil { data = composeTplData(subject, body, issue.HTMLURL()+"#"+comment.HashTag()) } else { diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index b95a74c3621db..e8fb42c492ea7 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -399,7 +399,7 @@ func trimCommitActionAppURLPrefix(x *xorm.Engine) error { return fmt.Errorf("marshal action content[%d]: %v", actID, err) } - if _, err = sess.Id(actID).Update(&Action{ + if _, err = sess.ID(actID).Update(&Action{ Content: string(p), }); err != nil { return fmt.Errorf("update action[%d]: %v", actID, err) @@ -503,7 +503,7 @@ func attachmentRefactor(x *xorm.Engine) error { // Update database first because this is where error happens the most often. for _, attach := range attachments { - if _, err = sess.Id(attach.ID).Update(attach); err != nil { + if _, err = sess.ID(attach.ID).Update(attach); err != nil { return err } @@ -581,7 +581,7 @@ func renamePullRequestFields(x *xorm.Engine) (err error) { if pull.Index == 0 { continue } - if _, err = sess.Id(pull.ID).Update(pull); err != nil { + if _, err = sess.ID(pull.ID).Update(pull); err != nil { return err } } @@ -661,7 +661,7 @@ func generateOrgRandsAndSalt(x *xorm.Engine) (err error) { if org.Salt, err = generate.GetRandomString(10); err != nil { return err } - if _, err = sess.Id(org.ID).Update(org); err != nil { + if _, err = sess.ID(org.ID).Update(org); err != nil { return err } } diff --git a/models/migrations/v27.go b/models/migrations/v27.go index bd115cf937275..e87c7ab68f582 100644 --- a/models/migrations/v27.go +++ b/models/migrations/v27.go @@ -58,13 +58,13 @@ func convertIntervalToDuration(x *xorm.Engine) (err error) { return fmt.Errorf("Query repositories: %v", err) } for _, mirror := range mirrors { - mirror.Interval = mirror.Interval * time.Hour + mirror.Interval *= time.Hour if mirror.Interval < setting.Mirror.MinInterval { log.Info("Mirror interval less than Mirror.MinInterval, setting default interval: repo id %v", mirror.RepoID) mirror.Interval = setting.Mirror.DefaultInterval } log.Debug("Mirror interval set to %v for repo id %v", mirror.Interval, mirror.RepoID) - _, err := sess.Id(mirror.ID).Cols("interval").Update(mirror) + _, err := sess.ID(mirror.ID).Cols("interval").Update(mirror) if err != nil { return fmt.Errorf("update mirror interval failed: %v", err) } diff --git a/models/migrations/v78.go b/models/migrations/v78.go index 7ca112dbd5005..310c479d01b74 100644 --- a/models/migrations/v78.go +++ b/models/migrations/v78.go @@ -48,6 +48,9 @@ func renameRepoIsBareToIsEmpty(x *xorm.Engine) error { if len(indexes) >= 1 { _, err = sess.Exec("DROP INDEX IDX_repository_is_bare ON repository") + if err != nil { + return fmt.Errorf("Drop index failed: %v", err) + } } } else { _, err = sess.Exec("DROP INDEX IDX_repository_is_bare ON repository") diff --git a/models/migrations/v85.go b/models/migrations/v85.go index 1fe85ac4087b8..d511628b8d544 100644 --- a/models/migrations/v85.go +++ b/models/migrations/v85.go @@ -58,6 +58,9 @@ func hashAppToken(x *xorm.Engine) error { if len(indexes) >= 1 { _, err = sess.Exec("DROP INDEX UQE_access_token_sha1 ON access_token") + if err != nil { + return err + } } } else { _, err = sess.Exec("DROP INDEX UQE_access_token_sha1 ON access_token") diff --git a/models/models.go b/models/models.go index c1d4c100d0027..5752a8edd6dcf 100644 --- a/models/models.go +++ b/models/models.go @@ -48,6 +48,7 @@ type Engine interface { Join(joinOperator string, tablename interface{}, condition string, args ...interface{}) *xorm.Session SQL(interface{}, ...interface{}) *xorm.Session Where(interface{}, ...interface{}) *xorm.Session + Asc(colNames ...string) *xorm.Session } var ( @@ -181,14 +182,14 @@ func parsePostgreSQLHostPort(info string) (string, string) { return host, port } -func getPostgreSQLConnectionString(DBHost, DBUser, DBPasswd, DBName, DBParam, DBSSLMode string) (connStr string) { - host, port := parsePostgreSQLHostPort(DBHost) +func getPostgreSQLConnectionString(dbHost, dbUser, dbPasswd, dbName, dbParam, dbsslMode string) (connStr string) { + host, port := parsePostgreSQLHostPort(dbHost) if host[0] == '/' { // looks like a unix socket connStr = fmt.Sprintf("postgres://%s:%s@:%s/%s%ssslmode=%s&host=%s", - url.PathEscape(DBUser), url.PathEscape(DBPasswd), port, DBName, DBParam, DBSSLMode, host) + url.PathEscape(dbUser), url.PathEscape(dbPasswd), port, dbName, dbParam, dbsslMode, host) } else { connStr = fmt.Sprintf("postgres://%s:%s@%s:%s/%s%ssslmode=%s", - url.PathEscape(DBUser), url.PathEscape(DBPasswd), host, port, DBName, DBParam, DBSSLMode) + url.PathEscape(dbUser), url.PathEscape(dbPasswd), host, port, dbName, dbParam, dbsslMode) } return } diff --git a/models/notification.go b/models/notification.go index cda2916faeb1d..f83fe63e5ac5a 100644 --- a/models/notification.go +++ b/models/notification.go @@ -119,7 +119,10 @@ func createOrUpdateIssueNotifications(e Engine, issue *Issue, notificationAuthor } } - issue.loadRepo(e) + err = issue.loadRepo(e) + if err != nil { + return err + } for _, watch := range watches { issue.Repo.Units = nil diff --git a/models/oauth2.go b/models/oauth2.go index 10bce31924862..bf4446229a422 100644 --- a/models/oauth2.go +++ b/models/oauth2.go @@ -106,7 +106,10 @@ func InitOAuth2() error { for _, source := range loginSources { oAuth2Config := source.OAuth2() - oauth2.RegisterProvider(source.Name, oAuth2Config.Provider, oAuth2Config.ClientID, oAuth2Config.ClientSecret, oAuth2Config.OpenIDConnectAutoDiscoveryURL, oAuth2Config.CustomURLMapping) + err := oauth2.RegisterProvider(source.Name, oAuth2Config.Provider, oAuth2Config.ClientID, oAuth2Config.ClientSecret, oAuth2Config.OpenIDConnectAutoDiscoveryURL, oAuth2Config.CustomURLMapping) + if err != nil { + return err + } } return nil } diff --git a/models/oauth2_application.go b/models/oauth2_application.go index 1e69dd6430464..63d2e7ce5eb4b 100644 --- a/models/oauth2_application.go +++ b/models/oauth2_application.go @@ -142,6 +142,9 @@ func GetOAuth2ApplicationByID(id int64) (app *OAuth2Application, err error) { func getOAuth2ApplicationByID(e Engine, id int64) (app *OAuth2Application, err error) { app = new(OAuth2Application) has, err := e.ID(id).Get(app) + if err != nil { + return nil, err + } if !has { return nil, ErrOAuthApplicationNotFound{ID: id} } @@ -295,10 +298,10 @@ func (code *OAuth2AuthorizationCode) invalidate(e Engine) error { // ValidateCodeChallenge validates the given verifier against the saved code challenge. This is part of the PKCE implementation. func (code *OAuth2AuthorizationCode) ValidateCodeChallenge(verifier string) bool { - return code.validateCodeChallenge(x, verifier) + return code.validateCodeChallenge(verifier) } -func (code *OAuth2AuthorizationCode) validateCodeChallenge(e Engine, verifier string) bool { +func (code *OAuth2AuthorizationCode) validateCodeChallenge(verifier string) bool { switch code.CodeChallengeMethod { case "S256": // base64url(SHA256(verifier)) see https://tools.ietf.org/html/rfc7636#section-4.6 diff --git a/models/org.go b/models/org.go index 6511072e2b7b0..65002eadff148 100644 --- a/models/org.go +++ b/models/org.go @@ -172,7 +172,9 @@ func CreateOrganization(org, owner *User) (err error) { } if _, err = sess.Insert(&units); err != nil { - sess.Rollback() + if err := sess.Rollback(); err != nil { + log.Error("CreateOrganization: sess.Rollback: %v", err) + } return err } @@ -376,10 +378,7 @@ func HasOrgVisible(org *User, user *User) bool { func hasOrgVisible(e Engine, org *User, user *User) bool { // Not SignedUser if user == nil { - if org.Visibility == structs.VisibleTypePublic { - return true - } - return false + return org.Visibility == structs.VisibleTypePublic } if user.IsAdmin { @@ -485,10 +484,14 @@ func AddOrgUser(orgID, uid int64) error { } if _, err := sess.Insert(ou); err != nil { - sess.Rollback() + if err := sess.Rollback(); err != nil { + log.Error("AddOrgUser: sess.Rollback: %v", err) + } return err } else if _, err = sess.Exec("UPDATE `user` SET num_members = num_members + 1 WHERE id = ?", orgID); err != nil { - sess.Rollback() + if err := sess.Rollback(); err != nil { + log.Error("AddOrgUser: sess.Rollback: %v", err) + } return err } diff --git a/models/org_team.go b/models/org_team.go index 49d06896e59d7..dcf07437403d3 100644 --- a/models/org_team.go +++ b/models/org_team.go @@ -287,7 +287,8 @@ func NewTeam(t *Team) (err error) { has, err := x.ID(t.OrgID).Get(new(User)) if err != nil { return err - } else if !has { + } + if !has { return ErrOrgNotExist{t.OrgID, ""} } @@ -298,7 +299,8 @@ func NewTeam(t *Team) (err error) { Get(new(Team)) if err != nil { return err - } else if has { + } + if has { return ErrTeamAlreadyExist{t.OrgID, t.LowerName} } @@ -309,7 +311,10 @@ func NewTeam(t *Team) (err error) { } if _, err = sess.Insert(t); err != nil { - sess.Rollback() + errRollback := sess.Rollback() + if errRollback != nil { + log.Error("NewTeam sess.Rollback: %v", errRollback) + } return err } @@ -319,14 +324,20 @@ func NewTeam(t *Team) (err error) { unit.TeamID = t.ID } if _, err = sess.Insert(&t.Units); err != nil { - sess.Rollback() + errRollback := sess.Rollback() + if errRollback != nil { + log.Error("NewTeam sess.Rollback: %v", errRollback) + } return err } } // Update organization number of teams. if _, err = sess.Exec("UPDATE `user` SET num_teams=num_teams+1 WHERE id = ?", t.OrgID); err != nil { - sess.Rollback() + errRollback := sess.Rollback() + if errRollback != nil { + log.Error("NewTeam sess.Rollback: %v", errRollback) + } return err } return sess.Commit() @@ -412,7 +423,10 @@ func UpdateTeam(t *Team, authChanged bool) (err error) { } if _, err = sess.Insert(&t.Units); err != nil { - sess.Rollback() + errRollback := sess.Rollback() + if errRollback != nil { + log.Error("UpdateTeam sess.Rollback: %v", errRollback) + } return err } } @@ -841,7 +855,10 @@ func UpdateTeamUnits(team *Team, units []TeamUnit) (err error) { } if _, err = sess.Insert(units); err != nil { - sess.Rollback() + errRollback := sess.Rollback() + if errRollback != nil { + log.Error("UpdateTeamUnits sess.Rollback: %v", errRollback) + } return err } diff --git a/models/org_test.go b/models/org_test.go index b484208be152d..a2ebf1f60bce8 100644 --- a/models/org_test.go +++ b/models/org_test.go @@ -242,10 +242,10 @@ func TestGetOrgByName(t *testing.T) { assert.EqualValues(t, 3, org.ID) assert.Equal(t, "user3", org.Name) - org, err = GetOrgByName("user2") // user2 is an individual + _, err = GetOrgByName("user2") // user2 is an individual assert.True(t, IsErrOrgNotExist(err)) - org, err = GetOrgByName("") // corner case + _, err = GetOrgByName("") // corner case assert.True(t, IsErrOrgNotExist(err)) } @@ -499,7 +499,7 @@ func TestAccessibleReposEnv_CountRepos(t *testing.T) { func TestAccessibleReposEnv_RepoIDs(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) org := AssertExistsAndLoadBean(t, &User{ID: 3}).(*User) - testSuccess := func(userID, page, pageSize int64, expectedRepoIDs []int64) { + testSuccess := func(userID, _, pageSize int64, expectedRepoIDs []int64) { env, err := org.AccessibleReposEnv(userID) assert.NoError(t, err) repoIDs, err := env.RepoIDs(1, 100) diff --git a/models/pull.go b/models/pull.go index 4c59ac045a51e..7dd611c8089ea 100644 --- a/models/pull.go +++ b/models/pull.go @@ -192,15 +192,19 @@ func (pr *PullRequest) apiFormat(e Engine) *api.PullRequest { } } if baseBranch, err = pr.BaseRepo.GetBranch(pr.BaseBranch); err != nil { + log.Error("pr.BaseRepo.GetBranch[%d]: %v", pr.BaseBranch, err) return nil } if baseCommit, err = baseBranch.GetCommit(); err != nil { + log.Error("baseBranch.GetCommit[%d]: %v", pr.ID, err) return nil } if headBranch, err = pr.HeadRepo.GetBranch(pr.HeadBranch); err != nil { + log.Error("pr.HeadRepo.GetBranch[%d]: %v", pr.HeadBranch, err) return nil } if headCommit, err = headBranch.GetCommit(); err != nil { + log.Error("headBranch.GetCommit[%d]: %v", pr.ID, err) return nil } apiBaseBranchInfo := &api.PRBranchInfo{ @@ -218,7 +222,10 @@ func (pr *PullRequest) apiFormat(e Engine) *api.PullRequest { Repository: pr.HeadRepo.innerAPIFormat(e, AccessModeNone, false), } - pr.Issue.loadRepo(e) + if err = pr.Issue.loadRepo(e); err != nil { + log.Error("pr.Issue.loadRepo[%d]: %v", pr.ID, err) + return nil + } apiPullRequest := &api.PullRequest{ ID: pr.ID, @@ -420,7 +427,11 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle if err != nil { return err } - defer RemoveTemporaryPath(tmpBasePath) + defer func() { + if err := RemoveTemporaryPath(tmpBasePath); err != nil { + log.Error("Merge: RemoveTemporaryPath: %s", err) + } + }() headRepoPath := RepoPath(pr.HeadUserName, pr.HeadRepo.Name) @@ -1142,10 +1153,11 @@ func (pr *PullRequest) UpdatePatch() (err error) { return fmt.Errorf("AddRemote: %v", err) } defer func() { - headGitRepo.RemoveRemote(tmpRemote) + if err := headGitRepo.RemoveRemote(tmpRemote); err != nil { + log.Error("UpdatePatch: RemoveRemote: %s", err) + } }() - remoteBranch := "remotes/" + tmpRemote + "/" + pr.BaseBranch - pr.MergeBase, err = headGitRepo.GetMergeBase(remoteBranch, pr.HeadBranch) + pr.MergeBase, _, err = headGitRepo.GetMergeBase(tmpRemote, pr.BaseBranch, pr.HeadBranch) if err != nil { return fmt.Errorf("GetMergeBase: %v", err) } else if err = pr.Update(); err != nil { @@ -1181,7 +1193,11 @@ func (pr *PullRequest) PushToBaseRepo() (err error) { return fmt.Errorf("headGitRepo.AddRemote: %v", err) } // Make sure to remove the remote even if the push fails - defer headGitRepo.RemoveRemote(tmpRemoteName) + defer func() { + if err := headGitRepo.RemoveRemote(tmpRemoteName); err != nil { + log.Error("PushToBaseRepo: RemoveRemote: %s", err) + } + }() headFile := pr.GetGitRefName() diff --git a/models/pull_test.go b/models/pull_test.go index 1dad664077711..5a53474ac4fc7 100644 --- a/models/pull_test.go +++ b/models/pull_test.go @@ -94,7 +94,7 @@ func TestGetUnmergedPullRequest(t *testing.T) { assert.NoError(t, err) assert.Equal(t, int64(2), pr.ID) - pr, err = GetUnmergedPullRequest(1, 9223372036854775807, "branch1", "master") + _, err = GetUnmergedPullRequest(1, 9223372036854775807, "branch1", "master") assert.Error(t, err) assert.True(t, IsErrPullRequestNotExist(err)) } @@ -128,7 +128,7 @@ func TestGetPullRequestByIndex(t *testing.T) { assert.Equal(t, int64(1), pr.BaseRepoID) assert.Equal(t, int64(2), pr.Index) - pr, err = GetPullRequestByIndex(9223372036854775807, 9223372036854775807) + _, err = GetPullRequestByIndex(9223372036854775807, 9223372036854775807) assert.Error(t, err) assert.True(t, IsErrPullRequestNotExist(err)) } @@ -151,7 +151,7 @@ func TestGetPullRequestByIssueID(t *testing.T) { assert.NoError(t, err) assert.Equal(t, int64(2), pr.IssueID) - pr, err = GetPullRequestByIssueID(9223372036854775807) + _, err = GetPullRequestByIssueID(9223372036854775807) assert.Error(t, err) assert.True(t, IsErrPullRequestNotExist(err)) } diff --git a/models/release.go b/models/release.go index b7ec4461f274c..28a2891013582 100644 --- a/models/release.go +++ b/models/release.go @@ -50,12 +50,12 @@ func (r *Release) loadAttributes(e Engine) error { } } if r.Publisher == nil { - r.Publisher, err = GetUserByID(r.PublisherID) + r.Publisher, err = getUserByID(e, r.PublisherID) if err != nil { return err } } - return GetReleaseAttachments(r) + return getReleaseAttachments(e, r) } // LoadAttributes load repo and publisher attributes for a release @@ -316,6 +316,10 @@ func (s releaseMetaSearch) Less(i, j int) bool { // GetReleaseAttachments retrieves the attachments for releases func GetReleaseAttachments(rels ...*Release) (err error) { + return getReleaseAttachments(x, rels...) +} + +func getReleaseAttachments(e Engine, rels ...*Release) (err error) { if len(rels) == 0 { return } @@ -335,11 +339,10 @@ func GetReleaseAttachments(rels ...*Release) (err error) { sort.Sort(sortedRels) // Select attachments - err = x. + err = e. Asc("release_id"). In("release_id", sortedRels.ID). Find(&attachments, Attachment{}) - if err != nil { return err } @@ -354,7 +357,6 @@ func GetReleaseAttachments(rels ...*Release) (err error) { } return - } type releaseSorter struct { @@ -493,7 +495,7 @@ func SyncReleasesWithTags(repo *Repository, gitRepo *git.Repository) error { return fmt.Errorf("GetTagCommitID: %v", err) } if git.IsErrNotExist(err) || commitID != rel.Sha1 { - if err := pushUpdateDeleteTag(repo, gitRepo, rel.TagName); err != nil { + if err := pushUpdateDeleteTag(repo, rel.TagName); err != nil { return fmt.Errorf("pushUpdateDeleteTag: %v", err) } } else { diff --git a/models/repo.go b/models/repo.go index d5eca3d22502e..8819debd4bcd0 100644 --- a/models/repo.go +++ b/models/repo.go @@ -20,7 +20,6 @@ import ( "os" "path" "path/filepath" - "regexp" "sort" "strconv" "strings" @@ -331,7 +330,7 @@ func (repo *Repository) innerAPIFormat(e Engine, mode AccessMode, isParent bool) AllowRebase: allowRebase, AllowRebaseMerge: allowRebaseMerge, AllowSquash: allowSquash, - AvatarURL: repo.AvatarLink(), + AvatarURL: repo.avatarLink(e), } } @@ -744,10 +743,6 @@ func (repo *Repository) getUsersWithAccessMode(e Engine, mode AccessMode) (_ []* return users, nil } -var ( - descPattern = regexp.MustCompile(`https?://\S+`) -) - // DescriptionHTML does special handles to description and return HTML string. func (repo *Repository) DescriptionHTML() template.HTML { desc, err := markup.RenderDescriptionHTML([]byte(repo.Description), repo.HTMLURL(), repo.ComposeMetas()) @@ -1333,11 +1328,9 @@ func createRepository(e *xorm.Session, doer, u *User, repo *Repository) (err err return fmt.Errorf("prepareWebhooks: %v", err) } go HookQueue.Add(repo.ID) - } else { + } else if err = repo.recalculateAccesses(e); err != nil { // Organization automatically called this in addRepository method. - if err = repo.recalculateAccesses(e); err != nil { - return fmt.Errorf("recalculateAccesses: %v", err) - } + return fmt.Errorf("recalculateAccesses: %v", err) } if setting.Service.AutoWatchNewRepos { @@ -1512,11 +1505,9 @@ func TransferOwnership(doer *User, newOwnerName string, repo *Repository) error } else if err = t.addRepository(sess, repo); err != nil { return fmt.Errorf("add to owner team: %v", err) } - } else { + } else if err = repo.recalculateAccesses(sess); err != nil { // Organization called this in addRepository method. - if err = repo.recalculateAccesses(sess); err != nil { - return fmt.Errorf("recalculateAccesses: %v", err) - } + return fmt.Errorf("recalculateAccesses: %v", err) } // Update repository count. @@ -1864,7 +1855,10 @@ func DeleteRepository(doer *User, uid, repoID int64) error { repoPath := repo.repoPath(sess) removeAllWithNotice(sess, "Delete repository files", repoPath) - repo.deleteWiki(sess) + err = repo.deleteWiki(sess) + if err != nil { + return err + } // Remove attachment files. for i := range attachmentPaths { @@ -2401,9 +2395,10 @@ func ForkRepository(doer, u *User, oldRepo *Repository, name, desc string) (_ *R return nil, err } if forkedRepo != nil { - return nil, ErrRepoAlreadyExist{ - Uname: u.Name, - Name: forkedRepo.Name, + return nil, ErrForkAlreadyExist{ + Uname: u.Name, + RepoName: oldRepo.FullName(), + ForkName: forkedRepo.FullName(), } } @@ -2522,17 +2517,13 @@ func (repo *Repository) GetUserFork(userID int64) (*Repository, error) { // CustomAvatarPath returns repository custom avatar file path. func (repo *Repository) CustomAvatarPath() string { // Avatar empty by default - if len(repo.Avatar) <= 0 { + if len(repo.Avatar) == 0 { return "" } return filepath.Join(setting.RepositoryAvatarUploadPath, repo.Avatar) } -// GenerateRandomAvatar generates a random avatar for repository. -func (repo *Repository) GenerateRandomAvatar() error { - return repo.generateRandomAvatar(x) -} - +// generateRandomAvatar generates a random avatar for repository. func (repo *Repository) generateRandomAvatar(e Engine) error { idToString := fmt.Sprintf("%d", repo.ID) @@ -2566,10 +2557,7 @@ func (repo *Repository) generateRandomAvatar(e Engine) error { // RemoveRandomAvatars removes the randomly generated avatars that were created for repositories func RemoveRandomAvatars() error { - var ( - err error - ) - err = x. + return x. Where("id > 0").BufferSize(setting.IterateBufferSize). Iterate(new(Repository), func(idx int, bean interface{}) error { @@ -2580,21 +2568,23 @@ func RemoveRandomAvatars() error { } return nil }) - return err } // RelAvatarLink returns a relative link to the repository's avatar. func (repo *Repository) RelAvatarLink() string { + return repo.relAvatarLink(x) +} +func (repo *Repository) relAvatarLink(e Engine) string { // If no avatar - path is empty avatarPath := repo.CustomAvatarPath() - if len(avatarPath) <= 0 || !com.IsFile(avatarPath) { + if len(avatarPath) == 0 || !com.IsFile(avatarPath) { switch mode := setting.RepositoryAvatarFallback; mode { case "image": return setting.RepositoryAvatarFallbackImage case "random": - if err := repo.GenerateRandomAvatar(); err != nil { - log.Error("GenerateRandomAvatar: %v", err) + if err := repo.generateRandomAvatar(e); err != nil { + log.Error("generateRandomAvatar: %v", err) } default: // default behaviour: do not display avatar @@ -2604,9 +2594,9 @@ func (repo *Repository) RelAvatarLink() string { return setting.AppSubURL + "/repo-avatars/" + repo.Avatar } -// AvatarLink returns user avatar absolute link. -func (repo *Repository) AvatarLink() string { - link := repo.RelAvatarLink() +// avatarLink returns user avatar absolute link. +func (repo *Repository) avatarLink(e Engine) string { + link := repo.relAvatarLink(e) // link may be empty! if len(link) > 0 { if link[0] == '/' && link[1] != '/' { diff --git a/models/repo_activity.go b/models/repo_activity.go index fb1385a54b12e..04612ae1efca0 100644 --- a/models/repo_activity.go +++ b/models/repo_activity.go @@ -114,7 +114,7 @@ func GetActivityStatsTopAuthors(repo *Repository, timeFrom time.Time, count int) v = append(v, u) } - sort.Slice(v[:], func(i, j int) bool { + sort.Slice(v, func(i, j int) bool { return v[i].Commits < v[j].Commits }) diff --git a/models/repo_branch.go b/models/repo_branch.go index 08c881fc24c29..dee6ef3d7e267 100644 --- a/models/repo_branch.go +++ b/models/repo_branch.go @@ -75,7 +75,11 @@ func (repo *Repository) CreateNewBranch(doer *User, oldBranchName, branchName st if err != nil { return err } - defer RemoveTemporaryPath(basePath) + defer func() { + if err := RemoveTemporaryPath(basePath); err != nil { + log.Error("CreateNewBranch: RemoveTemporaryPath: %s", err) + } + }() if err := git.Clone(repo.RepoPath(), basePath, git.CloneRepoOptions{ Bare: true, @@ -117,7 +121,11 @@ func (repo *Repository) CreateNewBranchFromCommit(doer *User, commit, branchName if err != nil { return err } - defer RemoveTemporaryPath(basePath) + defer func() { + if err := RemoveTemporaryPath(basePath); err != nil { + log.Error("CreateNewBranchFromCommit: RemoveTemporaryPath: %s", err) + } + }() if err := git.Clone(repo.RepoPath(), basePath, git.CloneRepoOptions{ Bare: true, diff --git a/models/repo_collaboration.go b/models/repo_collaboration.go index 9d2935d581d83..0797f504305f7 100644 --- a/models/repo_collaboration.go +++ b/models/repo_collaboration.go @@ -142,7 +142,7 @@ func (repo *Repository) ChangeCollaborationAccessMode(uid int64, mode AccessMode } if _, err = sess. - Id(collaboration.ID). + ID(collaboration.ID). Cols("mode"). Update(collaboration); err != nil { return fmt.Errorf("update collaboration: %v", err) diff --git a/models/repo_list.go b/models/repo_list.go index 9686676eae2cc..5655404f7c71f 100644 --- a/models/repo_list.go +++ b/models/repo_list.go @@ -148,19 +148,19 @@ func (s SearchOrderBy) String() string { // Strings for sorting result const ( SearchOrderByAlphabetically SearchOrderBy = "name ASC" - SearchOrderByAlphabeticallyReverse = "name DESC" - SearchOrderByLeastUpdated = "updated_unix ASC" - SearchOrderByRecentUpdated = "updated_unix DESC" - SearchOrderByOldest = "created_unix ASC" - SearchOrderByNewest = "created_unix DESC" - SearchOrderBySize = "size ASC" - SearchOrderBySizeReverse = "size DESC" - SearchOrderByID = "id ASC" - SearchOrderByIDReverse = "id DESC" - SearchOrderByStars = "num_stars ASC" - SearchOrderByStarsReverse = "num_stars DESC" - SearchOrderByForks = "num_forks ASC" - SearchOrderByForksReverse = "num_forks DESC" + SearchOrderByAlphabeticallyReverse SearchOrderBy = "name DESC" + SearchOrderByLeastUpdated SearchOrderBy = "updated_unix ASC" + SearchOrderByRecentUpdated SearchOrderBy = "updated_unix DESC" + SearchOrderByOldest SearchOrderBy = "created_unix ASC" + SearchOrderByNewest SearchOrderBy = "created_unix DESC" + SearchOrderBySize SearchOrderBy = "size ASC" + SearchOrderBySizeReverse SearchOrderBy = "size DESC" + SearchOrderByID SearchOrderBy = "id ASC" + SearchOrderByIDReverse SearchOrderBy = "id DESC" + SearchOrderByStars SearchOrderBy = "num_stars ASC" + SearchOrderByStarsReverse SearchOrderBy = "num_stars DESC" + SearchOrderByForks SearchOrderBy = "num_forks ASC" + SearchOrderByForksReverse SearchOrderBy = "num_forks DESC" ) // SearchRepositoryByName takes keyword and part of repository name to search, diff --git a/models/repo_redirect.go b/models/repo_redirect.go index 813b3e6c9e554..8847a0889c424 100644 --- a/models/repo_redirect.go +++ b/models/repo_redirect.go @@ -4,7 +4,10 @@ package models -import "strings" +import ( + "code.gitea.io/gitea/modules/log" + "strings" +) // RepoRedirect represents that a repo name should be redirected to another type RepoRedirect struct { @@ -38,7 +41,10 @@ func NewRepoRedirect(ownerID, repoID int64, oldRepoName, newRepoName string) err } if err := deleteRepoRedirect(sess, ownerID, newRepoName); err != nil { - sess.Rollback() + errRollback := sess.Rollback() + if errRollback != nil { + log.Error("NewRepoRedirect sess.Rollback: %v", errRollback) + } return err } @@ -47,7 +53,10 @@ func NewRepoRedirect(ownerID, repoID int64, oldRepoName, newRepoName string) err LowerName: oldRepoName, RedirectRepoID: repoID, }); err != nil { - sess.Rollback() + errRollback := sess.Rollback() + if errRollback != nil { + log.Error("NewRepoRedirect sess.Rollback: %v", errRollback) + } return err } return sess.Commit() diff --git a/models/repo_tag.go b/models/repo_tag.go index fa3f19bb292cb..3864b7a12a7c9 100644 --- a/models/repo_tag.go +++ b/models/repo_tag.go @@ -8,7 +8,7 @@ import ( "code.gitea.io/gitea/modules/git" ) -// GetTagsByPath returns repo tags by it's path +// GetTagsByPath returns repo tags by its path func GetTagsByPath(path string) ([]*git.Tag, error) { gitRepo, err := git.OpenRepository(path) if err != nil { diff --git a/models/repo_test.go b/models/repo_test.go index 8411536d70e23..02cb5ab993530 100644 --- a/models/repo_test.go +++ b/models/repo_test.go @@ -131,7 +131,7 @@ func TestForkRepository(t *testing.T) { fork, err := ForkRepository(user, user, repo, "test", "test") assert.Nil(t, fork) assert.Error(t, err) - assert.True(t, IsErrRepoAlreadyExist(err)) + assert.True(t, IsErrForkAlreadyExist(err)) } func TestRepoAPIURL(t *testing.T) { diff --git a/models/ssh_key.go b/models/ssh_key.go index fb5f9f399b757..1f2288b13ec42 100644 --- a/models/ssh_key.go +++ b/models/ssh_key.go @@ -142,7 +142,7 @@ func parseKeyString(content string) (string, error) { if continuationLine || strings.ContainsAny(line, ":-") { continuationLine = strings.HasSuffix(line, "\\") } else { - keyContent = keyContent + line + keyContent += line } } @@ -392,7 +392,7 @@ func addKey(e Engine, key *PublicKey) (err error) { } // AddPublicKey adds new public key to database and authorized_keys file. -func AddPublicKey(ownerID int64, name, content string, LoginSourceID int64) (*PublicKey, error) { +func AddPublicKey(ownerID int64, name, content string, loginSourceID int64) (*PublicKey, error) { log.Trace(content) fingerprint, err := calcFingerprint(content) @@ -427,7 +427,7 @@ func AddPublicKey(ownerID int64, name, content string, LoginSourceID int64) (*Pu Content: content, Mode: AccessModeWrite, Type: KeyTypeUser, - LoginSourceID: LoginSourceID, + LoginSourceID: loginSourceID, } if err = addKey(sess, key); err != nil { return nil, fmt.Errorf("addKey: %v", err) @@ -491,10 +491,10 @@ func ListPublicKeys(uid int64) ([]*PublicKey, error) { } // ListPublicLdapSSHKeys returns a list of synchronized public ldap ssh keys belongs to given user and login source. -func ListPublicLdapSSHKeys(uid int64, LoginSourceID int64) ([]*PublicKey, error) { +func ListPublicLdapSSHKeys(uid int64, loginSourceID int64) ([]*PublicKey, error) { keys := make([]*PublicKey, 0, 5) return keys, x. - Where("owner_id = ? AND login_source_id = ?", uid, LoginSourceID). + Where("owner_id = ? AND login_source_id = ?", uid, loginSourceID). Find(&keys) } diff --git a/models/status.go b/models/status.go index a3db47f45537b..384f5693dcf56 100644 --- a/models/status.go +++ b/models/status.go @@ -87,7 +87,7 @@ func (status *CommitStatus) loadRepo(e Engine) (err error) { // APIURL returns the absolute APIURL to this commit-status. func (status *CommitStatus) APIURL() string { - status.loadRepo(x) + _ = status.loadRepo(x) return fmt.Sprintf("%sapi/v1/%s/statuses/%s", setting.AppURL, status.Repo.FullName(), status.SHA) } @@ -95,7 +95,7 @@ func (status *CommitStatus) APIURL() string { // APIFormat assumes some fields assigned with values: // Required - Repo, Creator func (status *CommitStatus) APIFormat() *api.Status { - status.loadRepo(x) + _ = status.loadRepo(x) apiStatus := &api.Status{ Created: status.CreatedUnix.AsTime(), Updated: status.CreatedUnix.AsTime(), @@ -219,7 +219,9 @@ func newCommitStatus(sess *xorm.Session, opts NewCommitStatusOptions) error { } has, err := sess.Desc("index").Limit(1).Get(lastCommitStatus) if err != nil { - sess.Rollback() + if err := sess.Rollback(); err != nil { + log.Error("newCommitStatus: sess.Rollback: %v", err) + } return fmt.Errorf("newCommitStatus[%s, %s]: %v", repoPath, opts.SHA, err) } if has { @@ -231,7 +233,9 @@ func newCommitStatus(sess *xorm.Session, opts NewCommitStatusOptions) error { // Insert new CommitStatus if _, err = sess.Insert(opts.CommitStatus); err != nil { - sess.Rollback() + if err := sess.Rollback(); err != nil { + log.Error("newCommitStatus: sess.Rollback: %v", err) + } return fmt.Errorf("newCommitStatus[%s, %s]: %v", repoPath, opts.SHA, err) } diff --git a/models/token_test.go b/models/token_test.go index 9f2699a16862f..a74de8f81823f 100644 --- a/models/token_test.go +++ b/models/token_test.go @@ -36,11 +36,11 @@ func TestGetAccessTokenBySHA(t *testing.T) { assert.Equal(t, "2b3668e11cb82d3af8c6e4524fc7841297668f5008d1626f0ad3417e9fa39af84c268248b78c481daa7e5dc437784003494f", token.TokenHash) assert.Equal(t, "e4efbf36", token.TokenLastEight) - token, err = GetAccessTokenBySHA("notahash") + _, err = GetAccessTokenBySHA("notahash") assert.Error(t, err) assert.True(t, IsErrAccessTokenNotExist(err)) - token, err = GetAccessTokenBySHA("") + _, err = GetAccessTokenBySHA("") assert.Error(t, err) assert.True(t, IsErrAccessTokenEmpty(err)) } diff --git a/models/update.go b/models/update.go index 1492d6c0d351d..3eb0990d3dea9 100644 --- a/models/update.go +++ b/models/update.go @@ -84,7 +84,7 @@ func PushUpdate(branch string, opt PushUpdateOptions) error { return nil } -func pushUpdateDeleteTag(repo *Repository, gitRepo *git.Repository, tagName string) error { +func pushUpdateDeleteTag(repo *Repository, tagName string) error { rel, err := GetRelease(repo.ID, tagName) if err != nil { if IsErrReleaseNotExist(err) { @@ -223,7 +223,7 @@ func pushUpdate(opts PushUpdateOptions) (repo *Repository, err error) { // If is tag reference tagName := opts.RefFullName[len(git.TagPrefix):] if isDelRef { - err = pushUpdateDeleteTag(repo, gitRepo, tagName) + err = pushUpdateDeleteTag(repo, tagName) if err != nil { return nil, fmt.Errorf("pushUpdateDeleteTag: %v", err) } @@ -263,10 +263,6 @@ func pushUpdate(opts PushUpdateOptions) (repo *Repository, err error) { commits = ListToPushCommits(l) } - if opts.RefFullName == git.BranchPrefix+repo.DefaultBranch { - UpdateRepoIndexer(repo) - } - if err := CommitRepoAction(CommitRepoActionOptions{ PusherName: opts.PusherName, RepoOwnerID: owner.ID, diff --git a/models/user.go b/models/user.go index 9ee27ddfbd449..2820d2edbc0c6 100644 --- a/models/user.go +++ b/models/user.go @@ -1072,7 +1072,10 @@ func deleteUser(e *xorm.Session, u *User) error { if _, err = e.Delete(&PublicKey{OwnerID: u.ID}); err != nil { return fmt.Errorf("deletePublicKeys: %v", err) } - rewriteAllPublicKeys(e) + err = rewriteAllPublicKeys(e) + if err != nil { + return err + } // ***** END: PublicKey ***** // ***** START: GPGPublicKey ***** @@ -1334,6 +1337,19 @@ func GetUserByEmail(email string) (*User, error) { return GetUserByID(emailAddress.UID) } + // Finally, if email address is the protected email address: + if strings.HasSuffix(email, fmt.Sprintf("@%s", setting.Service.NoReplyAddress)) { + username := strings.TrimSuffix(email, fmt.Sprintf("@%s", setting.Service.NoReplyAddress)) + user := &User{LowerName: username} + has, err := x.Get(user) + if err != nil { + return nil, err + } + if has { + return user, nil + } + } + return nil, ErrUserNotExist{0, email, 0} } @@ -1388,8 +1404,7 @@ func (opts *SearchUserOptions) toConds() builder.Cond { } else { exprCond = builder.Expr("org_user.org_id = \"user\".id") } - var accessCond = builder.NewCond() - accessCond = builder.Or( + accessCond := builder.Or( builder.In("id", builder.Select("org_id").From("org_user").LeftJoin("`user`", exprCond).Where(builder.And(builder.Eq{"uid": opts.OwnerID}, builder.Eq{"visibility": structs.VisibleTypePrivate}))), builder.In("visibility", structs.VisibleTypePublic, structs.VisibleTypeLimited)) cond = cond.And(accessCond) @@ -1499,9 +1514,9 @@ func deleteKeysMarkedForDeletion(keys []string) (bool, error) { } // addLdapSSHPublicKeys add a users public keys. Returns true if there are changes. -func addLdapSSHPublicKeys(usr *User, s *LoginSource, SSHPublicKeys []string) bool { +func addLdapSSHPublicKeys(usr *User, s *LoginSource, sshPublicKeys []string) bool { var sshKeysNeedUpdate bool - for _, sshKey := range SSHPublicKeys { + for _, sshKey := range sshPublicKeys { _, _, _, _, err := ssh.ParseAuthorizedKey([]byte(sshKey)) if err == nil { sshKeyName := fmt.Sprintf("%s-%s", s.Name, sshKey[0:40]) @@ -1523,7 +1538,7 @@ func addLdapSSHPublicKeys(usr *User, s *LoginSource, SSHPublicKeys []string) boo } // synchronizeLdapSSHPublicKeys updates a users public keys. Returns true if there are changes. -func synchronizeLdapSSHPublicKeys(usr *User, s *LoginSource, SSHPublicKeys []string) bool { +func synchronizeLdapSSHPublicKeys(usr *User, s *LoginSource, sshPublicKeys []string) bool { var sshKeysNeedUpdate bool log.Trace("synchronizeLdapSSHPublicKeys[%s]: Handling LDAP Public SSH Key synchronization for user %s", s.Name, usr.Name) @@ -1541,7 +1556,7 @@ func synchronizeLdapSSHPublicKeys(usr *User, s *LoginSource, SSHPublicKeys []str // Get Public Keys from LDAP and skip duplicate keys var ldapKeys []string - for _, v := range SSHPublicKeys { + for _, v := range sshPublicKeys { sshKeySplit := strings.Split(v, " ") if len(sshKeySplit) > 1 { ldapKey := strings.Join(sshKeySplit[:2], " ") @@ -1621,9 +1636,13 @@ func SyncExternalUsers() { // Find all users with this login type var users []*User - x.Where("login_type = ?", LoginLDAP). + err = x.Where("login_type = ?", LoginLDAP). And("login_source = ?", s.ID). Find(&users) + if err != nil { + log.Error("SyncExternalUsers: %v", err) + return + } sr := s.LDAP().SearchEntries() for _, su := range sr { @@ -1681,7 +1700,7 @@ func SyncExternalUsers() { // Check if user data has changed if (len(s.LDAP().AdminFilter) > 0 && usr.IsAdmin != su.IsAdmin) || - strings.ToLower(usr.Email) != strings.ToLower(su.Mail) || + !strings.EqualFold(usr.Email, su.Mail) || usr.FullName != fullName || !usr.IsActive { @@ -1705,7 +1724,10 @@ func SyncExternalUsers() { // Rewrite authorized_keys file if LDAP Public SSH Key attribute is set and any key was added or removed if sshKeysNeedUpdate { - RewriteAllPublicKeys() + err = RewriteAllPublicKeys() + if err != nil { + log.Error("RewriteAllPublicKeys: %v", err) + } } // Deactivate users not present in LDAP diff --git a/models/user_mail.go b/models/user_mail.go index 39d1070c35e9c..d929ba5a5d892 100644 --- a/models/user_mail.go +++ b/models/user_mail.go @@ -134,7 +134,7 @@ func (email *EmailAddress) Activate() error { email.IsActivated = true if _, err := sess. - Id(email.ID). + ID(email.ID). Cols("is_activated"). Update(email); err != nil { return err diff --git a/models/user_openid_test.go b/models/user_openid_test.go index 711f92b9ffe65..18f84bef760b2 100644 --- a/models/user_openid_test.go +++ b/models/user_openid_test.go @@ -31,12 +31,12 @@ func TestGetUserOpenIDs(t *testing.T) { func TestGetUserByOpenID(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) - user, err := GetUserByOpenID("https://unknown") + _, err := GetUserByOpenID("https://unknown") if assert.Error(t, err) { assert.True(t, IsErrUserNotExist(err)) } - user, err = GetUserByOpenID("https://user1.domain1.tld") + user, err := GetUserByOpenID("https://user1.domain1.tld") if assert.NoError(t, err) { assert.Equal(t, user.ID, int64(1)) } diff --git a/models/webhook.go b/models/webhook.go index 7a28e37958b96..e3e11e59633f4 100644 --- a/models/webhook.go +++ b/models/webhook.go @@ -700,7 +700,10 @@ func prepareWebhook(e Engine, w *Webhook, repo *Repository, event HookEventType, log.Error("prepareWebhooks.JSONPayload: %v", err) } sig := hmac.New(sha256.New, []byte(w.Secret)) - sig.Write(data) + _, err = sig.Write(data) + if err != nil { + log.Error("prepareWebhooks.sigWrite: %v", err) + } signature = hex.EncodeToString(sig.Sum(nil)) } @@ -930,8 +933,7 @@ func InitDeliverHooks() { return nil, err } - conn.SetDeadline(time.Now().Add(timeout)) - return conn, nil + return conn, conn.SetDeadline(time.Now().Add(timeout)) }, }, diff --git a/models/webhook_discord.go b/models/webhook_discord.go index 0029e94fca421..d7a2de0d1168e 100644 --- a/models/webhook_discord.go +++ b/models/webhook_discord.go @@ -490,7 +490,7 @@ func getDiscordReleasePayload(p *api.ReleasePayload, meta *DiscordMeta) (*Discor Embeds: []DiscordEmbed{ { Title: title, - Description: fmt.Sprintf("%s", p.Release.Note), + Description: p.Release.Note, URL: url, Color: color, Author: DiscordEmbedAuthor{ diff --git a/models/wiki.go b/models/wiki.go index bcf97c076573b..9ae3386333298 100644 --- a/models/wiki.go +++ b/models/wiki.go @@ -115,7 +115,11 @@ func (repo *Repository) updateWikiPage(doer *User, oldWikiName, newWikiName, con if err != nil { return err } - defer RemoveTemporaryPath(basePath) + defer func() { + if err := RemoveTemporaryPath(basePath); err != nil { + log.Error("Merge: RemoveTemporaryPath: %s", err) + } + }() cloneOpts := git.CloneRepoOptions{ Bare: true, @@ -246,7 +250,11 @@ func (repo *Repository) DeleteWikiPage(doer *User, wikiName string) (err error) if err != nil { return err } - defer RemoveTemporaryPath(basePath) + defer func() { + if err := RemoveTemporaryPath(basePath); err != nil { + log.Error("Merge: RemoveTemporaryPath: %s", err) + } + }() if err := git.Clone(repo.WikiPath(), basePath, git.CloneRepoOptions{ Bare: true, diff --git a/modules/auth/auth.go b/modules/auth/auth.go index edb596c240496..2a2ee404928cb 100644 --- a/modules/auth/auth.go +++ b/modules/auth/auth.go @@ -214,10 +214,8 @@ func SignedInUser(ctx *macaron.Context, sess session.Store) (*models.User, bool) if err = models.UpdateAccessToken(token); err != nil { log.Error("UpdateAccessToken: %v", err) } - } else { - if !models.IsErrAccessTokenNotExist(err) && !models.IsErrAccessTokenEmpty(err) { - log.Error("GetAccessTokenBySha: %v", err) - } + } else if !models.IsErrAccessTokenNotExist(err) && !models.IsErrAccessTokenEmpty(err) { + log.Error("GetAccessTokenBySha: %v", err) } if u == nil { @@ -301,12 +299,6 @@ func GetInclude(field reflect.StructField) string { return getRuleBody(field, "Include(") } -// FIXME: struct contains a struct -func validateStruct(obj interface{}) binding.Errors { - - return nil -} - func validate(errs binding.Errors, data map[string]interface{}, f Form, l macaron.Locale) binding.Errors { if errs.Len() == 0 { return errs diff --git a/modules/auth/oauth2/oauth2.go b/modules/auth/oauth2/oauth2.go index 5684f44a89b8f..a2d7116211cf7 100644 --- a/modules/auth/oauth2/oauth2.go +++ b/modules/auth/oauth2/oauth2.go @@ -220,8 +220,7 @@ func GetDefaultProfileURL(provider string) string { // GetDefaultEmailURL return the default email url for the given provider func GetDefaultEmailURL(provider string) string { - switch provider { - case "github": + if provider == "github" { return github.EmailURL } return "" diff --git a/modules/auth/openid/discovery_cache_test.go b/modules/auth/openid/discovery_cache_test.go index 2e37058cc3f5f..931e5c7945e33 100644 --- a/modules/auth/openid/discovery_cache_test.go +++ b/modules/auth/openid/discovery_cache_test.go @@ -39,7 +39,7 @@ func TestTimedDiscoveryCache(t *testing.T) { t.Errorf("Expected nil, got %v", di) } - // Sleep one second and try retrive again + // Sleep one second and try retrieve again time.Sleep(1 * time.Second) if di := dc.Get("foo"); di != nil { diff --git a/modules/auth/user_form.go b/modules/auth/user_form.go index 8b9e5877d9565..0c8bd30abc8d3 100644 --- a/modules/auth/user_form.go +++ b/modules/auth/user_form.go @@ -253,7 +253,7 @@ func (f UpdateThemeForm) IsThemeExists() bool { var exists bool for _, v := range setting.UI.Themes { - if strings.ToLower(v) == strings.ToLower(f.Theme) { + if strings.EqualFold(v, f.Theme) { exists = true break } diff --git a/modules/base/base.go b/modules/base/base.go index 0ba72c328e268..026f68f646ce3 100644 --- a/modules/base/base.go +++ b/modules/base/base.go @@ -4,9 +4,6 @@ package base -// DocURL api doc url -const DocURL = "https://godoc.org/github.com/go-gitea/go-sdk/gitea" - type ( // TplName template relative path type TplName string diff --git a/modules/base/tool.go b/modules/base/tool.go index dcf9155a07750..4893abff71ddf 100644 --- a/modules/base/tool.go +++ b/modules/base/tool.go @@ -44,21 +44,21 @@ var UTF8BOM = []byte{'\xef', '\xbb', '\xbf'} // EncodeMD5 encodes string to md5 hex value. func EncodeMD5(str string) string { m := md5.New() - m.Write([]byte(str)) + _, _ = m.Write([]byte(str)) return hex.EncodeToString(m.Sum(nil)) } // EncodeSha1 string to sha1 hex value. func EncodeSha1(str string) string { h := sha1.New() - h.Write([]byte(str)) + _, _ = h.Write([]byte(str)) return hex.EncodeToString(h.Sum(nil)) } // EncodeSha256 string to sha1 hex value. func EncodeSha256(str string) string { h := sha256.New() - h.Write([]byte(str)) + _, _ = h.Write([]byte(str)) return hex.EncodeToString(h.Sum(nil)) } @@ -193,7 +193,7 @@ func CreateTimeLimitCode(data string, minutes int, startInf interface{}) string // create sha1 encode string sh := sha1.New() - sh.Write([]byte(data + setting.SecretKey + startStr + endStr + com.ToStr(minutes))) + _, _ = sh.Write([]byte(data + setting.SecretKey + startStr + endStr + com.ToStr(minutes))) encoded := hex.EncodeToString(sh.Sum(nil)) code := fmt.Sprintf("%s%06d%s", startStr, minutes, encoded) @@ -425,16 +425,6 @@ const ( EByte = PByte * 1024 ) -var bytesSizeTable = map[string]uint64{ - "b": Byte, - "kb": KByte, - "mb": MByte, - "gb": GByte, - "tb": TByte, - "pb": PByte, - "eb": EByte, -} - func logn(n, b float64) float64 { return math.Log(n) / math.Log(b) } @@ -582,27 +572,27 @@ func IsTextFile(data []byte) bool { if len(data) == 0 { return true } - return strings.Index(http.DetectContentType(data), "text/") != -1 + return strings.Contains(http.DetectContentType(data), "text/") } // IsImageFile detects if data is an image format func IsImageFile(data []byte) bool { - return strings.Index(http.DetectContentType(data), "image/") != -1 + return strings.Contains(http.DetectContentType(data), "image/") } // IsPDFFile detects if data is a pdf format func IsPDFFile(data []byte) bool { - return strings.Index(http.DetectContentType(data), "application/pdf") != -1 + return strings.Contains(http.DetectContentType(data), "application/pdf") } // IsVideoFile detects if data is an video format func IsVideoFile(data []byte) bool { - return strings.Index(http.DetectContentType(data), "video/") != -1 + return strings.Contains(http.DetectContentType(data), "video/") } // IsAudioFile detects if data is an video format func IsAudioFile(data []byte) bool { - return strings.Index(http.DetectContentType(data), "audio/") != -1 + return strings.Contains(http.DetectContentType(data), "audio/") } // EntryIcon returns the octicon class for displaying files/directories diff --git a/modules/base/tool_test.go b/modules/base/tool_test.go index ec9bc1eb52335..fa61e5dfb16d4 100644 --- a/modules/base/tool_test.go +++ b/modules/base/tool_test.go @@ -287,20 +287,19 @@ func TestHtmlTimeSince(t *testing.T) { } func TestFileSize(t *testing.T) { - var size int64 - size = 512 + var size int64 = 512 assert.Equal(t, "512B", FileSize(size)) - size = size * 1024 + size *= 1024 assert.Equal(t, "512KB", FileSize(size)) - size = size * 1024 + size *= 1024 assert.Equal(t, "512MB", FileSize(size)) - size = size * 1024 + size *= 1024 assert.Equal(t, "512GB", FileSize(size)) - size = size * 1024 + size *= 1024 assert.Equal(t, "512TB", FileSize(size)) - size = size * 1024 + size *= 1024 assert.Equal(t, "512PB", FileSize(size)) - size = size * 4 + size *= 4 assert.Equal(t, "2.0EB", FileSize(size)) } diff --git a/modules/cache/cache.go b/modules/cache/cache.go index a2d6c724c851a..a7412f109f108 100644 --- a/modules/cache/cache.go +++ b/modules/cache/cache.go @@ -43,7 +43,10 @@ func GetInt(key string, getFunc func() (int, error)) (int, error) { if value, err = getFunc(); err != nil { return value, err } - conn.Put(key, value, int64(setting.CacheService.TTL.Seconds())) + err = conn.Put(key, value, int64(setting.CacheService.TTL.Seconds())) + if err != nil { + return 0, err + } } switch value := conn.Get(key).(type) { case int: @@ -72,7 +75,10 @@ func GetInt64(key string, getFunc func() (int64, error)) (int64, error) { if value, err = getFunc(); err != nil { return value, err } - conn.Put(key, value, int64(setting.CacheService.TTL.Seconds())) + err = conn.Put(key, value, int64(setting.CacheService.TTL.Seconds())) + if err != nil { + return 0, err + } } switch value := conn.Get(key).(type) { case int64: @@ -93,5 +99,5 @@ func Remove(key string) { if conn == nil { return } - conn.Delete(key) + _ = conn.Delete(key) } diff --git a/modules/context/api.go b/modules/context/api.go index 61f651475937b..9be3fb512cf3c 100644 --- a/modules/context/api.go +++ b/modules/context/api.go @@ -7,14 +7,11 @@ package context import ( "fmt" - "net/url" - "path" "strings" "github.com/go-macaron/csrf" "code.gitea.io/gitea/models" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" @@ -76,7 +73,7 @@ func (ctx *APIContext) Error(status int, title string, obj interface{}) { ctx.JSON(status, APIError{ Message: message, - URL: base.DocURL, + URL: setting.API.SwaggerURL, }) } @@ -180,15 +177,9 @@ func (ctx *APIContext) NotFound(objs ...interface{}) { } } - u, err := url.Parse(setting.AppURL) - if err != nil { - ctx.Error(500, "Invalid AppURL", err) - return - } - u.Path = path.Join(u.Path, "api", "swagger") ctx.JSON(404, map[string]interface{}{ "message": message, - "documentation_url": u.String(), + "documentation_url": setting.API.SwaggerURL, "errors": errors, }) } diff --git a/modules/context/context.go b/modules/context/context.go index 1699d7aeccb7d..b7c77ac4605ee 100644 --- a/modules/context/context.go +++ b/modules/context/context.go @@ -130,7 +130,6 @@ func (ctx *Context) RedirectToFirst(location ...string) { } ctx.Redirect(setting.AppSubURL + "/") - return } // HTML calls Context.HTML and converts template name to string. @@ -266,7 +265,7 @@ func Contexter() macaron.Handler { } c.Header().Set("Content-Type", "text/html") c.WriteHeader(http.StatusOK) - c.Write([]byte(com.Expand(` + _, _ = c.Write([]byte(com.Expand(`
diff --git a/modules/context/pagination.go b/modules/context/pagination.go index 4795f650fb850..390b4dbdd7073 100644 --- a/modules/context/pagination.go +++ b/modules/context/pagination.go @@ -39,7 +39,7 @@ func (p *Pagination) AddParam(ctx *Context, paramKey string, ctxKey string) { // GetParams returns the configured URL params func (p *Pagination) GetParams() template.URL { - return template.URL(strings.Join(p.urlParams[:], "&")) + return template.URL(strings.Join(p.urlParams, "&")) } // SetDefaultParams sets common pagination params that are often used diff --git a/modules/context/repo.go b/modules/context/repo.go index 0908340879cb0..096f3c0a5d216 100644 --- a/modules/context/repo.go +++ b/modules/context/repo.go @@ -455,15 +455,13 @@ func RepoAssignment() macaron.Handler { ctx.Repo.PullRequest.BaseRepo = repo.BaseRepo ctx.Repo.PullRequest.Allowed = true ctx.Repo.PullRequest.HeadInfo = ctx.Repo.Owner.Name + ":" + ctx.Repo.BranchName - } else { + } else if repo.AllowsPulls() { // Or, this is repository accepts pull requests between branches. - if repo.AllowsPulls() { - ctx.Data["BaseRepo"] = repo - ctx.Repo.PullRequest.BaseRepo = repo - ctx.Repo.PullRequest.Allowed = true - ctx.Repo.PullRequest.SameRepo = true - ctx.Repo.PullRequest.HeadInfo = ctx.Repo.BranchName - } + ctx.Data["BaseRepo"] = repo + ctx.Repo.PullRequest.BaseRepo = repo + ctx.Repo.PullRequest.Allowed = true + ctx.Repo.PullRequest.SameRepo = true + ctx.Repo.PullRequest.HeadInfo = ctx.Repo.BranchName } } ctx.Data["PullRequestCtx"] = ctx.Repo.PullRequest diff --git a/modules/git/blob.go b/modules/git/blob.go index 171b4a1010d85..73ac89dfdf98e 100644 --- a/modules/git/blob.go +++ b/modules/git/blob.go @@ -50,12 +50,12 @@ func (b *Blob) GetBlobContentBase64() (string, error) { go func() { _, err := io.Copy(encoder, dataRc) - encoder.Close() + _ = encoder.Close() if err != nil { - pw.CloseWithError(err) + _ = pw.CloseWithError(err) } else { - pw.Close() + _ = pw.Close() } }() diff --git a/modules/git/commit.go b/modules/git/commit.go index 7b64a300ab1be..c86ece984883b 100644 --- a/modules/git/commit.go +++ b/modules/git/commit.go @@ -133,7 +133,7 @@ func (c *Commit) ParentCount() int { func isImageFile(data []byte) (string, bool) { contentType := http.DetectContentType(data) - if strings.Index(contentType, "image/") != -1 { + if strings.Contains(contentType, "image/") { return contentType, true } return contentType, false @@ -206,8 +206,7 @@ func CommitChanges(repoPath string, opts CommitChangesOptions) error { } func commitsCount(repoPath, revision, relpath string) (int64, error) { - var cmd *Command - cmd = NewCommand("rev-list", "--count") + cmd := NewCommand("rev-list", "--count") cmd.AddArguments(revision) if len(relpath) > 0 { cmd.AddArguments("--", relpath) @@ -263,7 +262,7 @@ type SearchCommitsOptions struct { All bool } -// NewSearchCommitsOptions contruct a SearchCommitsOption from a space-delimited search string +// NewSearchCommitsOptions construct a SearchCommitsOption from a space-delimited search string func NewSearchCommitsOptions(searchString string, forAllRefs bool) SearchCommitsOptions { var keywords, authors, committers []string var after, before string diff --git a/modules/git/commit_info.go b/modules/git/commit_info.go index da430a21cddbc..43723d169b7a5 100644 --- a/modules/git/commit_info.go +++ b/modules/git/commit_info.go @@ -87,16 +87,6 @@ func getCommitTree(c *object.Commit, treePath string) (*object.Tree, error) { return tree, nil } -func getFullPath(treePath, path string) string { - if treePath != "" { - if path != "" { - return treePath + "/" + path - } - return treePath - } - return path -} - func getFileHashes(c *object.Commit, treePath string, paths []string) (map[string]plumbing.Hash, error) { tree, err := getCommitTree(c, treePath) if err == object.ErrDirectoryNotFound { diff --git a/modules/git/repo.go b/modules/git/repo.go index 4be3164130795..f5d7ee63bb256 100644 --- a/modules/git/repo.go +++ b/modules/git/repo.go @@ -58,21 +58,21 @@ func (repo *Repository) parsePrettyFormatLogToList(logs []byte) (*list.List, err // IsRepoURLAccessible checks if given repository URL is accessible. func IsRepoURLAccessible(url string) bool { _, err := NewCommand("ls-remote", "-q", "-h", url, "HEAD").Run() - if err != nil { - return false - } - return true + return err == nil } // InitRepository initializes a new Git repository. func InitRepository(repoPath string, bare bool) error { - os.MkdirAll(repoPath, os.ModePerm) + err := os.MkdirAll(repoPath, os.ModePerm) + if err != nil { + return err + } cmd := NewCommand("init") if bare { cmd.AddArguments("--bare") } - _, err := cmd.RunInDir(repoPath) + _, err = cmd.RunInDir(repoPath) return err } diff --git a/modules/git/repo_branch.go b/modules/git/repo_branch.go index 116bdbee823c7..05eba1e30ed66 100644 --- a/modules/git/repo_branch.go +++ b/modules/git/repo_branch.go @@ -29,10 +29,7 @@ func IsBranchExist(repoPath, name string) bool { // IsBranchExist returns true if given branch exists in current repository. func (repo *Repository) IsBranchExist(name string) bool { _, err := repo.gogitRepo.Reference(plumbing.ReferenceName(BranchPrefix+name), true) - if err != nil { - return false - } - return true + return err == nil } // Branch represents a Git branch. @@ -77,7 +74,7 @@ func (repo *Repository) GetBranches() ([]string, error) { return nil, err } - branches.ForEach(func(branch *plumbing.Reference) error { + _ = branches.ForEach(func(branch *plumbing.Reference) error { branchNames = append(branchNames, strings.TrimPrefix(branch.Name().String(), BranchPrefix)) return nil }) diff --git a/modules/git/repo_commit.go b/modules/git/repo_commit.go index b631f9341e18e..8ea2a331458b4 100644 --- a/modules/git/repo_commit.go +++ b/modules/git/repo_commit.go @@ -27,6 +27,13 @@ func (repo *Repository) GetRefCommitID(name string) (string, error) { return ref.Hash().String(), nil } +// IsCommitExist returns true if given commit exists in current repository. +func (repo *Repository) IsCommitExist(name string) bool { + hash := plumbing.NewHash(name) + _, err := repo.gogitRepo.CommitObject(hash) + return err == nil +} + // GetBranchCommitID returns last commit ID string of given branch. func (repo *Repository) GetBranchCommitID(name string) (string, error) { return repo.GetRefCommitID(BranchPrefix + name) diff --git a/modules/git/repo_compare.go b/modules/git/repo_compare.go new file mode 100644 index 0000000000000..ddc81097208b6 --- /dev/null +++ b/modules/git/repo_compare.go @@ -0,0 +1,112 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Copyright 2019 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" + "container/list" + "fmt" + "io" + "strconv" + "strings" + "time" + + logger "code.gitea.io/gitea/modules/log" +) + +// CompareInfo represents needed information for comparing references. +type CompareInfo struct { + MergeBase string + Commits *list.List + NumFiles int +} + +// GetMergeBase checks and returns merge base of two branches and the reference used as base. +func (repo *Repository) GetMergeBase(tmpRemote string, base, head string) (string, string, error) { + if tmpRemote == "" { + tmpRemote = "origin" + } + + if tmpRemote != "origin" { + tmpBaseName := "refs/remotes/" + tmpRemote + "/tmp_" + base + // Fetch commit into a temporary branch in order to be able to handle commits and tags + _, err := NewCommand("fetch", tmpRemote, base+":"+tmpBaseName).RunInDir(repo.Path) + if err == nil { + base = tmpBaseName + } + } + + stdout, err := NewCommand("merge-base", base, head).RunInDir(repo.Path) + return strings.TrimSpace(stdout), base, err +} + +// GetCompareInfo generates and returns compare information between base and head branches of repositories. +func (repo *Repository) GetCompareInfo(basePath, baseBranch, headBranch string) (_ *CompareInfo, err error) { + var ( + remoteBranch string + tmpRemote string + ) + + // We don't need a temporary remote for same repository. + if repo.Path != basePath { + // Add a temporary remote + tmpRemote = strconv.FormatInt(time.Now().UnixNano(), 10) + if err = repo.AddRemote(tmpRemote, basePath, true); err != nil { + return nil, fmt.Errorf("AddRemote: %v", err) + } + defer func() { + if err := repo.RemoveRemote(tmpRemote); err != nil { + logger.Error("GetPullRequestInfo: RemoveRemote: %v", err) + } + }() + } + + compareInfo := new(CompareInfo) + compareInfo.MergeBase, remoteBranch, err = repo.GetMergeBase(tmpRemote, baseBranch, headBranch) + if err == nil { + // We have a common base + logs, err := NewCommand("log", compareInfo.MergeBase+"..."+headBranch, prettyLogFormat).RunInDirBytes(repo.Path) + if err != nil { + return nil, err + } + compareInfo.Commits, err = repo.parsePrettyFormatLogToList(logs) + if err != nil { + return nil, fmt.Errorf("parsePrettyFormatLogToList: %v", err) + } + } else { + compareInfo.Commits = list.New() + compareInfo.MergeBase, err = GetFullCommitID(repo.Path, remoteBranch) + if err != nil { + compareInfo.MergeBase = remoteBranch + } + } + + // Count number of changed files. + stdout, err := NewCommand("diff", "--name-only", remoteBranch+"..."+headBranch).RunInDir(repo.Path) + if err != nil { + return nil, err + } + compareInfo.NumFiles = len(strings.Split(stdout, "\n")) - 1 + + return compareInfo, nil +} + +// GetPatch generates and returns patch data between given revisions. +func (repo *Repository) GetPatch(base, head string) ([]byte, error) { + return NewCommand("diff", "-p", "--binary", base, head).RunInDirBytes(repo.Path) +} + +// GetFormatPatch generates and returns format-patch data between given revisions. +func (repo *Repository) GetFormatPatch(base, head string) (io.Reader, error) { + stdout := new(bytes.Buffer) + stderr := new(bytes.Buffer) + + if err := NewCommand("format-patch", "--binary", "--stdout", base+"..."+head). + RunInDirPipeline(repo.Path, stdout, stderr); err != nil { + return nil, concatenateError(err, stderr.String()) + } + return stdout, nil +} diff --git a/modules/git/repo_pull_test.go b/modules/git/repo_compare_test.go similarity index 100% rename from modules/git/repo_pull_test.go rename to modules/git/repo_compare_test.go diff --git a/modules/git/repo_pull.go b/modules/git/repo_pull.go deleted file mode 100644 index 65c54145518d3..0000000000000 --- a/modules/git/repo_pull.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2015 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 git - -import ( - "bytes" - "container/list" - "fmt" - "io" - "strconv" - "strings" - "time" -) - -// PullRequestInfo represents needed information for a pull request. -type PullRequestInfo struct { - MergeBase string - Commits *list.List - NumFiles int -} - -// GetMergeBase checks and returns merge base of two branches. -func (repo *Repository) GetMergeBase(base, head string) (string, error) { - stdout, err := NewCommand("merge-base", base, head).RunInDir(repo.Path) - return strings.TrimSpace(stdout), err -} - -// GetPullRequestInfo generates and returns pull request information -// between base and head branches of repositories. -func (repo *Repository) GetPullRequestInfo(basePath, baseBranch, headBranch string) (_ *PullRequestInfo, err error) { - var remoteBranch string - - // We don't need a temporary remote for same repository. - if repo.Path != basePath { - // Add a temporary remote - tmpRemote := strconv.FormatInt(time.Now().UnixNano(), 10) - if err = repo.AddRemote(tmpRemote, basePath, true); err != nil { - return nil, fmt.Errorf("AddRemote: %v", err) - } - defer repo.RemoveRemote(tmpRemote) - - remoteBranch = "remotes/" + tmpRemote + "/" + baseBranch - } else { - remoteBranch = baseBranch - } - - prInfo := new(PullRequestInfo) - prInfo.MergeBase, err = repo.GetMergeBase(remoteBranch, headBranch) - if err == nil { - // We have a common base - logs, err := NewCommand("log", prInfo.MergeBase+"..."+headBranch, prettyLogFormat).RunInDirBytes(repo.Path) - if err != nil { - return nil, err - } - prInfo.Commits, err = repo.parsePrettyFormatLogToList(logs) - if err != nil { - return nil, fmt.Errorf("parsePrettyFormatLogToList: %v", err) - } - } else { - prInfo.Commits = list.New() - prInfo.MergeBase, err = GetFullCommitID(repo.Path, remoteBranch) - if err != nil { - prInfo.MergeBase = remoteBranch - } - } - - // Count number of changed files. - stdout, err := NewCommand("diff", "--name-only", remoteBranch+"..."+headBranch).RunInDir(repo.Path) - if err != nil { - return nil, err - } - prInfo.NumFiles = len(strings.Split(stdout, "\n")) - 1 - - return prInfo, nil -} - -// GetPatch generates and returns patch data between given revisions. -func (repo *Repository) GetPatch(base, head string) ([]byte, error) { - return NewCommand("diff", "-p", "--binary", base, head).RunInDirBytes(repo.Path) -} - -// GetFormatPatch generates and returns format-patch data between given revisions. -func (repo *Repository) GetFormatPatch(base, head string) (io.Reader, error) { - stdout := new(bytes.Buffer) - stderr := new(bytes.Buffer) - - if err := NewCommand("format-patch", "--binary", "--stdout", base+"..."+head). - RunInDirPipeline(repo.Path, stdout, stderr); err != nil { - return nil, concatenateError(err, stderr.String()) - } - return stdout, nil -} diff --git a/modules/git/repo_ref.go b/modules/git/repo_ref.go index e1ab46e0902dc..95a6c2ae69390 100644 --- a/modules/git/repo_ref.go +++ b/modules/git/repo_ref.go @@ -31,15 +31,19 @@ func (repo *Repository) GetRefsFiltered(pattern string) ([]*Reference, error) { if err = refsIter.ForEach(func(ref *plumbing.Reference) error { if ref.Name() != plumbing.HEAD && !ref.Name().IsRemote() && (pattern == "" || strings.HasPrefix(ref.Name().String(), pattern)) { + refType := string(ObjectCommit) + if ref.Name().IsTag() { + // tags can be of type `commit` (lightweight) or `tag` (annotated) + if tagType, _ := repo.GetTagType(SHA1(ref.Hash())); err == nil { + refType = tagType + } + } r := &Reference{ Name: ref.Name().String(), Object: SHA1(ref.Hash()), - Type: string(ObjectCommit), + Type: refType, repo: repo, } - if ref.Name().IsTag() { - r.Type = string(ObjectTag) - } refs = append(refs, r) } return nil diff --git a/modules/git/repo_tag.go b/modules/git/repo_tag.go index 8c72528933ccd..df49e9acd6dd5 100644 --- a/modules/git/repo_tag.go +++ b/modules/git/repo_tag.go @@ -6,6 +6,7 @@ package git import ( + "fmt" "strings" "github.com/mcuadros/go-version" @@ -23,10 +24,7 @@ func IsTagExist(repoPath, name string) bool { // IsTagExist returns true if given tag exists in the repository. func (repo *Repository) IsTagExist(name string) bool { _, err := repo.gogitRepo.Reference(plumbing.ReferenceName(TagPrefix+name), true) - if err != nil { - return false - } - return true + return err == nil } // CreateTag create one tag in the repository @@ -35,34 +33,78 @@ func (repo *Repository) CreateTag(name, revision string) error { return err } +// CreateAnnotatedTag create one annotated tag in the repository +func (repo *Repository) CreateAnnotatedTag(name, message, revision string) error { + _, err := NewCommand("tag", "-a", "-m", message, name, revision).RunInDir(repo.Path) + return err +} + func (repo *Repository) getTag(id SHA1) (*Tag, error) { t, ok := repo.tagCache.Get(id.String()) if ok { log("Hit cache: %s", id) - return t.(*Tag), nil + tagClone := *t.(*Tag) + return &tagClone, nil } - // Get tag type - tp, err := NewCommand("cat-file", "-t", id.String()).RunInDir(repo.Path) + // Get tag name + name, err := repo.GetTagNameBySHA(id.String()) + if err != nil { + return nil, err + } + + tp, err := repo.GetTagType(id) + if err != nil { + return nil, err + } + + // Get the commit ID and tag ID (may be different for annotated tag) for the returned tag object + commitIDStr, err := repo.GetTagCommitID(name) + if err != nil { + // every tag should have a commit ID so return all errors + return nil, err + } + commitID, err := NewIDFromString(commitIDStr) if err != nil { return nil, err } - tp = strings.TrimSpace(tp) - // Tag is a commit. + // tagID defaults to the commit ID as the tag ID and then tries to get a tag ID (only annotated tags) + tagID := commitID + if tagIDStr, err := repo.GetTagID(name); err != nil { + // if the err is NotExist then we can ignore and just keep tagID as ID (is lightweight tag) + // all other errors we return + if !IsErrNotExist(err) { + return nil, err + } + } else { + tagID, err = NewIDFromString(tagIDStr) + if err != nil { + return nil, err + } + } + + // If type is "commit, the tag is a lightweight tag if ObjectType(tp) == ObjectCommit { + commit, err := repo.GetCommit(id.String()) + if err != nil { + return nil, err + } tag := &Tag{ - ID: id, - Object: id, - Type: string(ObjectCommit), - repo: repo, + Name: name, + ID: tagID, + Object: commitID, + Type: string(ObjectCommit), + Tagger: commit.Committer, + Message: commit.Message(), + repo: repo, } repo.tagCache.Set(id.String(), tag) return tag, nil } - // Tag with message. + // The tag is an annotated tag with a message. data, err := NewCommand("cat-file", "-p", id.String()).RunInDirBytes(repo.Path) if err != nil { return nil, err @@ -73,16 +115,57 @@ func (repo *Repository) getTag(id SHA1) (*Tag, error) { return nil, err } + tag.Name = name tag.ID = id tag.repo = repo + tag.Type = tp repo.tagCache.Set(id.String(), tag) return tag, nil } +// GetTagNameBySHA returns the name of a tag from its tag object SHA or commit SHA +func (repo *Repository) GetTagNameBySHA(sha string) (string, error) { + if len(sha) < 5 { + return "", fmt.Errorf("SHA is too short: %s", sha) + } + + stdout, err := NewCommand("show-ref", "--tags", "-d").RunInDir(repo.Path) + if err != nil { + return "", err + } + + tagRefs := strings.Split(stdout, "\n") + for _, tagRef := range tagRefs { + if len(strings.TrimSpace(tagRef)) > 0 { + fields := strings.Fields(tagRef) + if strings.HasPrefix(fields[0], sha) && strings.HasPrefix(fields[1], TagPrefix) { + name := fields[1][len(TagPrefix):] + // annotated tags show up twice, their name for commit ID is suffixed with ^{} + name = strings.TrimSuffix(name, "^{}") + return name, nil + } + } + } + return "", ErrNotExist{ID: sha} +} + +// GetTagID returns the object ID for a tag (annotated tags have both an object SHA AND a commit SHA) +func (repo *Repository) GetTagID(name string) (string, error) { + stdout, err := NewCommand("show-ref", name).RunInDir(repo.Path) + if err != nil { + return "", err + } + fields := strings.Fields(stdout) + if len(fields) != 2 { + return "", ErrNotExist{ID: name} + } + return fields[0], nil +} + // GetTag returns a Git tag by given name. func (repo *Repository) GetTag(name string) (*Tag, error) { - idStr, err := repo.GetTagCommitID(name) + idStr, err := repo.GetTagID(name) if err != nil { return nil, err } @@ -96,7 +179,6 @@ func (repo *Repository) GetTag(name string) (*Tag, error) { if err != nil { return nil, err } - tag.Name = name return tag, nil } @@ -108,7 +190,7 @@ func (repo *Repository) GetTagInfos() ([]*Tag, error) { return nil, err } - tagNames := strings.Split(stdout, "\n") + tagNames := strings.Split(strings.TrimRight(stdout, "\n"), "\n") var tags = make([]*Tag, 0, len(tagNames)) for _, tagName := range tagNames { tagName = strings.TrimSpace(tagName) @@ -120,6 +202,7 @@ func (repo *Repository) GetTagInfos() ([]*Tag, error) { if err != nil { return nil, err } + tag.Name = tagName tags = append(tags, tag) } sortTagsByTime(tags) @@ -135,7 +218,7 @@ func (repo *Repository) GetTags() ([]string, error) { return nil, err } - tags.ForEach(func(tag *plumbing.Reference) error { + _ = tags.ForEach(func(tag *plumbing.Reference) error { tagNames = append(tagNames, strings.TrimPrefix(tag.Name().String(), TagPrefix)) return nil }) @@ -150,3 +233,38 @@ func (repo *Repository) GetTags() ([]string, error) { return tagNames, nil } + +// GetTagType gets the type of the tag, either commit (simple) or tag (annotated) +func (repo *Repository) GetTagType(id SHA1) (string, error) { + // Get tag type + stdout, err := NewCommand("cat-file", "-t", id.String()).RunInDir(repo.Path) + if err != nil { + return "", err + } + if len(stdout) == 0 { + return "", ErrNotExist{ID: id.String()} + } + return strings.TrimSpace(stdout), nil +} + +// GetAnnotatedTag returns a Git tag by its SHA, must be an annotated tag +func (repo *Repository) GetAnnotatedTag(sha string) (*Tag, error) { + id, err := NewIDFromString(sha) + if err != nil { + return nil, err + } + + // Tag type must be "tag" (annotated) and not a "commit" (lightweight) tag + if tagType, err := repo.GetTagType(id); err != nil { + return nil, err + } else if ObjectType(tagType) != ObjectTag { + // not an annotated tag + return nil, ErrNotExist{ID: id.String()} + } + + tag, err := repo.getTag(id) + if err != nil { + return nil, err + } + return tag, nil +} diff --git a/modules/git/repo_tag_test.go b/modules/git/repo_tag_test.go index ccb2d57ac2401..4f727c6c66fa8 100644 --- a/modules/git/repo_tag_test.go +++ b/modules/git/repo_tag_test.go @@ -21,8 +21,8 @@ func TestRepository_GetTags(t *testing.T) { assert.NoError(t, err) assert.Len(t, tags, 1) assert.EqualValues(t, "test", tags[0].Name) - assert.EqualValues(t, "37991dec2c8e592043f47155ce4808d4580f9123", tags[0].ID.String()) - assert.EqualValues(t, "commit", tags[0].Type) + assert.EqualValues(t, "3ad28a9149a2864384548f3d17ed7f38014c9e8a", tags[0].ID.String()) + assert.EqualValues(t, "tag", tags[0].Type) } func TestRepository_GetTag(t *testing.T) { @@ -35,10 +35,78 @@ func TestRepository_GetTag(t *testing.T) { bareRepo1, err := OpenRepository(clonedPath) assert.NoError(t, err) - tag, err := bareRepo1.GetTag("test") + lTagCommitID := "6fbd69e9823458e6c4a2fc5c0f6bc022b2f2acd1" + lTagName := "lightweightTag" + bareRepo1.CreateTag(lTagName, lTagCommitID) + + aTagCommitID := "8006ff9adbf0cb94da7dad9e537e53817f9fa5c0" + aTagName := "annotatedTag" + aTagMessage := "my annotated message" + bareRepo1.CreateAnnotatedTag(aTagName, aTagMessage, aTagCommitID) + aTagID, _ := bareRepo1.GetTagID(aTagName) + + lTag, err := bareRepo1.GetTag(lTagName) + lTag.repo = nil + assert.NoError(t, err) + assert.NotNil(t, lTag) + assert.EqualValues(t, lTagName, lTag.Name) + assert.EqualValues(t, lTagCommitID, lTag.ID.String()) + assert.EqualValues(t, lTagCommitID, lTag.Object.String()) + assert.EqualValues(t, "commit", lTag.Type) + + aTag, err := bareRepo1.GetTag(aTagName) + assert.NoError(t, err) + assert.NotNil(t, aTag) + assert.EqualValues(t, aTagName, aTag.Name) + assert.EqualValues(t, aTagID, aTag.ID.String()) + assert.NotEqual(t, aTagID, aTag.Object.String()) + assert.EqualValues(t, aTagCommitID, aTag.Object.String()) + assert.EqualValues(t, "tag", aTag.Type) +} + +func TestRepository_GetAnnotatedTag(t *testing.T) { + bareRepo1Path := filepath.Join(testReposDir, "repo1_bare") + + clonedPath, err := cloneRepo(bareRepo1Path, testReposDir, "repo1_TestRepository_GetTag") + assert.NoError(t, err) + defer os.RemoveAll(clonedPath) + + bareRepo1, err := OpenRepository(clonedPath) + assert.NoError(t, err) + + lTagCommitID := "6fbd69e9823458e6c4a2fc5c0f6bc022b2f2acd1" + lTagName := "lightweightTag" + bareRepo1.CreateTag(lTagName, lTagCommitID) + + aTagCommitID := "8006ff9adbf0cb94da7dad9e537e53817f9fa5c0" + aTagName := "annotatedTag" + aTagMessage := "my annotated message" + bareRepo1.CreateAnnotatedTag(aTagName, aTagMessage, aTagCommitID) + aTagID, _ := bareRepo1.GetTagID(aTagName) + + // Try an annotated tag + tag, err := bareRepo1.GetAnnotatedTag(aTagID) assert.NoError(t, err) assert.NotNil(t, tag) - assert.EqualValues(t, "test", tag.Name) - assert.EqualValues(t, "37991dec2c8e592043f47155ce4808d4580f9123", tag.ID.String()) - assert.EqualValues(t, "commit", tag.Type) + assert.EqualValues(t, aTagName, tag.Name) + assert.EqualValues(t, aTagID, tag.ID.String()) + assert.EqualValues(t, "tag", tag.Type) + + // Annotated tag's Commit ID should fail + tag2, err := bareRepo1.GetAnnotatedTag(aTagCommitID) + assert.Error(t, err) + assert.True(t, IsErrNotExist(err)) + assert.Nil(t, tag2) + + // Annotated tag's name should fail + tag3, err := bareRepo1.GetAnnotatedTag(aTagName) + assert.Error(t, err) + assert.Errorf(t, err, "Length must be 40: %d", len(aTagName)) + assert.Nil(t, tag3) + + // Lightweight Tag should fail + tag4, err := bareRepo1.GetAnnotatedTag(lTagCommitID) + assert.Error(t, err) + assert.True(t, IsErrNotExist(err)) + assert.Nil(t, tag4) } diff --git a/modules/git/submodule.go b/modules/git/submodule.go index 294df3986aded..6fc2e2444fc08 100644 --- a/modules/git/submodule.go +++ b/modules/git/submodule.go @@ -1,10 +1,19 @@ +// Copyright 2019 The Gitea Authors. All rights reserved. // Copyright 2015 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 git -import "strings" +import ( + "fmt" + "net" + "net/url" + "regexp" + "strings" +) + +var scpSyntax = regexp.MustCompile(`^([a-zA-Z0-9_]+@)?([a-zA-Z0-9._-]+):(.*)$`) // SubModule submodule is a reference on git repository type SubModule struct { @@ -34,46 +43,73 @@ func getRefURL(refURL, urlPrefix, parentPath string) string { return "" } - url := strings.TrimSuffix(refURL, ".git") - - // git://xxx/user/repo - if strings.HasPrefix(url, "git://") { - return "http://" + strings.TrimPrefix(url, "git://") - } + refURI := strings.TrimSuffix(refURL, ".git") - // http[s]://xxx/user/repo - if strings.HasPrefix(url, "http://") || strings.HasPrefix(url, "https://") { - return url + prefixURL, _ := url.Parse(urlPrefix) + urlPrefixHostname, _, err := net.SplitHostPort(prefixURL.Host) + if err != nil { + urlPrefixHostname = prefixURL.Host } // Relative url prefix check (according to git submodule documentation) - if strings.HasPrefix(url, "./") || strings.HasPrefix(url, "../") { + if strings.HasPrefix(refURI, "./") || strings.HasPrefix(refURI, "../") { // ...construct and return correct submodule url here... idx := strings.Index(parentPath, "/src/") if idx == -1 { - return url + return refURI } - return strings.TrimSuffix(urlPrefix, "/") + parentPath[:idx] + "/" + url + return strings.TrimSuffix(urlPrefix, "/") + parentPath[:idx] + "/" + refURI } - // sysuser@xxx:user/repo - i := strings.Index(url, "@") - j := strings.LastIndex(url, ":") + if !strings.Contains(refURI, "://") { + // scp style syntax which contains *no* port number after the : (and is not parsed by net/url) + // ex: git@try.gitea.io:go-gitea/gitea + match := scpSyntax.FindAllStringSubmatch(refURI, -1) + if len(match) > 0 { - // Only process when i < j because git+ssh://git@git.forwardbias.in/npploader.git - if i > -1 && j > -1 && i < j { - // fix problem with reverse proxy works only with local server - if strings.Contains(urlPrefix, url[i+1:j]) { - return urlPrefix + url[j+1:] + m := match[0] + refHostname := m[2] + path := m[3] + + if !strings.HasPrefix(path, "/") { + path = "/" + path + } + + if urlPrefixHostname == refHostname { + return prefixURL.Scheme + "://" + urlPrefixHostname + path + } + return "http://" + refHostname + path } - if strings.HasPrefix(url, "ssh://") || strings.HasPrefix(url, "git+ssh://") { - k := strings.Index(url[j+1:], "/") - return "http://" + url[i+1:j] + "/" + url[j+1:][k+1:] + } + + ref, err := url.Parse(refURI) + if err != nil { + return "" + } + + refHostname, _, err := net.SplitHostPort(ref.Host) + if err != nil { + refHostname = ref.Host + } + + supportedSchemes := []string{"http", "https", "git", "ssh", "git+ssh"} + + for _, scheme := range supportedSchemes { + if ref.Scheme == scheme { + if urlPrefixHostname == refHostname { + return prefixURL.Scheme + "://" + prefixURL.Host + ref.Path + } else if ref.Scheme == "http" || ref.Scheme == "https" { + if len(ref.User.Username()) > 0 { + return ref.Scheme + "://" + fmt.Sprintf("%v", ref.User) + "@" + ref.Host + ref.Path + } + return ref.Scheme + "://" + ref.Host + ref.Path + } else { + return "http://" + refHostname + ref.Path + } } - return "http://" + url[i+1:j] + "/" + url[j+1:] } - return url + return "" } // RefURL guesses and returns reference URL. diff --git a/modules/git/submodule_test.go b/modules/git/submodule_test.go index 6a3bb7ec7bab9..fd6c2aa95569d 100644 --- a/modules/git/submodule_test.go +++ b/modules/git/submodule_test.go @@ -19,8 +19,19 @@ func TestGetRefURL(t *testing.T) { }{ {"git://github.com/user1/repo1", "/", "/", "http://github.com/user1/repo1"}, {"https://localhost/user1/repo1.git", "/", "/", "https://localhost/user1/repo1"}, - {"git@github.com/user1/repo1.git", "/", "/", "git@github.com/user1/repo1"}, + {"http://localhost/user1/repo1.git", "/", "/", "http://localhost/user1/repo1"}, + {"git@github.com:user1/repo1.git", "/", "/", "http://github.com/user1/repo1"}, {"ssh://git@git.zefie.net:2222/zefie/lge_g6_kernel_scripts.git", "/", "/", "http://git.zefie.net/zefie/lge_g6_kernel_scripts"}, + {"git@git.zefie.net:2222/zefie/lge_g6_kernel_scripts.git", "/", "/", "http://git.zefie.net/2222/zefie/lge_g6_kernel_scripts"}, + {"git@try.gitea.io:go-gitea/gitea", "https://try.gitea.io/go-gitea/gitea", "/", "https://try.gitea.io/go-gitea/gitea"}, + {"ssh://git@try.gitea.io:9999/go-gitea/gitea", "https://try.gitea.io/go-gitea/gitea", "/", "https://try.gitea.io/go-gitea/gitea"}, + {"git://git@try.gitea.io:9999/go-gitea/gitea", "https://try.gitea.io/go-gitea/log", "/", "https://try.gitea.io/go-gitea/gitea"}, + {"ssh://git@127.0.0.1:9999/go-gitea/gitea", "https://127.0.0.1:3000/go-gitea/log", "/", "https://127.0.0.1:3000/go-gitea/gitea"}, + {"https://gitea.com:3000/user1/repo1.git", "https://127.0.0.1:3000/go-gitea/gitea", "/", "https://gitea.com:3000/user1/repo1"}, + {"https://username:password@github.com/username/repository.git", "/", "/", "https://username:password@github.com/username/repository"}, + {"somethingbad", "https://127.0.0.1:3000/go-gitea/gitea", "/", ""}, + {"git@localhost:user/repo", "https://localhost/user/repo2", "/", "https://localhost/user/repo"}, + {"../path/to/repo.git/", "https://localhost/user/repo2/src/branch/master/test", "/", "../path/to/repo.git/"}, } for _, kase := range kases { diff --git a/modules/git/tag.go b/modules/git/tag.go index 500fd274914c4..c97f574fa62b9 100644 --- a/modules/git/tag.go +++ b/modules/git/tag.go @@ -7,6 +7,7 @@ package git import ( "bytes" "sort" + "strings" ) // Tag represents a Git tag. @@ -59,7 +60,7 @@ l: } nextline += eol + 1 case eol == 0: - tag.Message = string(data[nextline+1:]) + tag.Message = strings.TrimRight(string(data[nextline+1:]), "\n") break l default: break l diff --git a/modules/git/utils.go b/modules/git/utils.go index 8f010321cf836..83cd21f34e77c 100644 --- a/modules/git/utils.go +++ b/modules/git/utils.go @@ -7,7 +7,6 @@ package git import ( "fmt" "os" - "path/filepath" "strings" "sync" ) @@ -75,13 +74,6 @@ func concatenateError(err error, stderr string) error { return fmt.Errorf("%v - %s", err, stderr) } -// If the object is stored in its own file (i.e not in a pack file), -// this function returns the full path to the object file. -// It does not test if the file exists. -func filepathFromSHA1(rootdir, sha1 string) string { - return filepath.Join(rootdir, "objects", sha1[:2], sha1[2:]) -} - // RefEndName return the end name of a ref name func RefEndName(refStr string) string { if strings.HasPrefix(refStr, BranchPrefix) { diff --git a/modules/gzip/gzip.go b/modules/gzip/gzip.go index 4a4a797c7aac0..0d1007183027d 100644 --- a/modules/gzip/gzip.go +++ b/modules/gzip/gzip.go @@ -74,7 +74,6 @@ func (wp *WriterPool) Put(w *gzip.Writer) { } var writerPool WriterPool -var regex regexp.Regexp // Options represents the configuration for the gzip middleware type Options struct { @@ -116,7 +115,7 @@ func Middleware(options ...Options) macaron.Handler { if rangeHdr := ctx.Req.Header.Get(rangeHeader); rangeHdr != "" { match := regex.FindStringSubmatch(rangeHdr) - if match != nil && len(match) > 1 { + if len(match) > 1 { return } } @@ -270,9 +269,8 @@ func (proxy *ProxyResponseWriter) Close() error { if proxy.writer == nil { err := proxy.startPlain() - if err != nil { - err = fmt.Errorf("GzipMiddleware: write to regular responseWriter at close gets error: %q", err.Error()) + return fmt.Errorf("GzipMiddleware: write to regular responseWriter at close gets error: %q", err.Error()) } } diff --git a/modules/highlight/highlight.go b/modules/highlight/highlight.go index 6d5e1a97ba769..cb52f6ac2ea9e 100644 --- a/modules/highlight/highlight.go +++ b/modules/highlight/highlight.go @@ -51,6 +51,7 @@ var ( ".php": {}, ".py": {}, ".rb": {}, + ".rs": {}, ".scss": {}, ".sql": {}, ".scala": {}, diff --git a/modules/httplib/httplib.go b/modules/httplib/httplib.go index c96e04c35fee2..90bbe8f12af2b 100644 --- a/modules/httplib/httplib.go +++ b/modules/httplib/httplib.go @@ -263,7 +263,7 @@ func (r *Request) getResponse() (*http.Response, error) { } if r.req.Method == "GET" && len(paramBody) > 0 { - if strings.Index(r.url, "?") != -1 { + if strings.Contains(r.url, "?") { r.url += "&" + paramBody } else { r.url = r.url + "?" + paramBody @@ -290,10 +290,13 @@ func (r *Request) getResponse() (*http.Response, error) { } } for k, v := range r.params { - bodyWriter.WriteField(k, v) + err := bodyWriter.WriteField(k, v) + if err != nil { + log.Fatal(err) + } } - bodyWriter.Close() - pw.Close() + _ = bodyWriter.Close() + _ = pw.Close() }() r.Header("Content-Type", bodyWriter.FormDataContentType()) r.req.Body = ioutil.NopCloser(pr) @@ -323,18 +326,15 @@ func (r *Request) getResponse() (*http.Response, error) { Proxy: proxy, Dial: TimeoutDialer(r.setting.ConnectTimeout, r.setting.ReadWriteTimeout), } - } else { - // if r.transport is *http.Transport then set the settings. - if t, ok := trans.(*http.Transport); ok { - if t.TLSClientConfig == nil { - t.TLSClientConfig = r.setting.TLSClientConfig - } - if t.Proxy == nil { - t.Proxy = r.setting.Proxy - } - if t.Dial == nil { - t.Dial = TimeoutDialer(r.setting.ConnectTimeout, r.setting.ReadWriteTimeout) - } + } else if t, ok := trans.(*http.Transport); ok { + if t.TLSClientConfig == nil { + t.TLSClientConfig = r.setting.TLSClientConfig + } + if t.Proxy == nil { + t.Proxy = r.setting.Proxy + } + if t.Dial == nil { + t.Dial = TimeoutDialer(r.setting.ConnectTimeout, r.setting.ReadWriteTimeout) } } @@ -461,7 +461,6 @@ func TimeoutDialer(cTimeout time.Duration, rwTimeout time.Duration) func(net, ad if err != nil { return nil, err } - conn.SetDeadline(time.Now().Add(rwTimeout)) - return conn, nil + return conn, conn.SetDeadline(time.Now().Add(rwTimeout)) } } diff --git a/modules/indexer/indexer.go b/modules/indexer/indexer.go index 9e12a7f5013b1..29261c693b592 100644 --- a/modules/indexer/indexer.go +++ b/modules/indexer/indexer.go @@ -5,7 +5,6 @@ package indexer import ( - "fmt" "os" "strconv" @@ -24,15 +23,6 @@ func indexerID(id int64) string { return strconv.FormatInt(id, 36) } -// idOfIndexerID the integer id associated with an indexer id -func idOfIndexerID(indexerID string) (int64, error) { - id, err := strconv.ParseInt(indexerID, 36, 64) - if err != nil { - return 0, fmt.Errorf("Unexpected indexer ID %s: %v", indexerID, err) - } - return id, nil -} - // numericEqualityQuery a numeric equality query for the given value and field func numericEqualityQuery(value int64, field string) *query.NumericRangeQuery { f := float64(value) @@ -42,13 +32,6 @@ func numericEqualityQuery(value int64, field string) *query.NumericRangeQuery { return q } -func newMatchPhraseQuery(matchPhrase, field, analyzer string) *query.MatchPhraseQuery { - q := bleve.NewMatchPhraseQuery(matchPhrase) - q.FieldVal = field - q.Analyzer = analyzer - return q -} - const unicodeNormalizeName = "unicodeNormalize" func addUnicodeNormalizeTokenFilter(m *mapping.IndexMappingImpl) error { diff --git a/modules/indexer/issues/indexer.go b/modules/indexer/issues/indexer.go index 75e6893b87d52..df8bfd6305912 100644 --- a/modules/indexer/issues/indexer.go +++ b/modules/indexer/issues/indexer.go @@ -101,7 +101,12 @@ func InitIssueIndexer(syncReindex bool) error { return fmt.Errorf("Unsupported indexer queue type: %v", setting.Indexer.IssueQueueType) } - go issueIndexerQueue.Run() + go func() { + err = issueIndexerQueue.Run() + if err != nil { + log.Error("issueIndexerQueue.Run: %v", err) + } + }() if populate { if syncReindex { @@ -161,7 +166,7 @@ func UpdateIssueIndexer(issue *models.Issue) { comments = append(comments, comment.Content) } } - issueIndexerQueue.Push(&IndexerData{ + _ = issueIndexerQueue.Push(&IndexerData{ ID: issue.ID, RepoID: issue.RepoID, Title: issue.Title, @@ -179,11 +184,11 @@ func DeleteRepoIssueIndexer(repo *models.Repository) { return } - if len(ids) <= 0 { + if len(ids) == 0 { return } - issueIndexerQueue.Push(&IndexerData{ + _ = issueIndexerQueue.Push(&IndexerData{ IDs: ids, IsDelete: true, }) diff --git a/modules/indexer/issues/queue_channel.go b/modules/indexer/issues/queue_channel.go index bd92f6b7b114c..b6458d3eb53db 100644 --- a/modules/indexer/issues/queue_channel.go +++ b/modules/indexer/issues/queue_channel.go @@ -34,20 +34,20 @@ func (c *ChannelQueue) Run() error { select { case data := <-c.queue: if data.IsDelete { - c.indexer.Delete(data.IDs...) + _ = c.indexer.Delete(data.IDs...) continue } datas = append(datas, data) if len(datas) >= c.batchNumber { - c.indexer.Index(datas) + _ = c.indexer.Index(datas) // TODO: save the point datas = make([]*IndexerData, 0, c.batchNumber) } case <-time.After(time.Millisecond * 100): i++ if i >= 3 && len(datas) > 0 { - c.indexer.Index(datas) + _ = c.indexer.Index(datas) // TODO: save the point datas = make([]*IndexerData, 0, c.batchNumber) } diff --git a/modules/indexer/issues/queue_disk.go b/modules/indexer/issues/queue_disk.go index cf9e6aee225a6..e5ac2a79812ae 100644 --- a/modules/indexer/issues/queue_disk.go +++ b/modules/indexer/issues/queue_disk.go @@ -44,7 +44,7 @@ func (l *LevelQueue) Run() error { for { i++ if len(datas) > l.batchNumber || (len(datas) > 0 && i > 3) { - l.indexer.Index(datas) + _ = l.indexer.Index(datas) datas = make([]*IndexerData, 0, l.batchNumber) i = 0 continue @@ -59,7 +59,7 @@ func (l *LevelQueue) Run() error { continue } - if len(bs) <= 0 { + if len(bs) == 0 { time.Sleep(time.Millisecond * 100) continue } diff --git a/modules/indexer/issues/queue_redis.go b/modules/indexer/issues/queue_redis.go index a9434c4f92610..aeccd7920ce8f 100644 --- a/modules/indexer/issues/queue_redis.go +++ b/modules/indexer/issues/queue_redis.go @@ -96,12 +96,12 @@ func (r *RedisQueue) Run() error { i++ if len(datas) > r.batchNumber || (len(datas) > 0 && i > 3) { - r.indexer.Index(datas) + _ = r.indexer.Index(datas) datas = make([]*IndexerData, 0, r.batchNumber) i = 0 } - if len(bs) <= 0 { + if len(bs) == 0 { time.Sleep(time.Millisecond * 100) continue } diff --git a/modules/lfs/locks.go b/modules/lfs/locks.go index b1ca2f094a25f..4516ba01aee53 100644 --- a/modules/lfs/locks.go +++ b/modules/lfs/locks.go @@ -17,7 +17,7 @@ import ( ) //checkIsValidRequest check if it a valid request in case of bad request it write the response to ctx. -func checkIsValidRequest(ctx *context.Context, post bool) bool { +func checkIsValidRequest(ctx *context.Context) bool { if !setting.LFS.StartServer { writeStatus(ctx, 404) return false @@ -35,13 +35,6 @@ func checkIsValidRequest(ctx *context.Context, post bool) bool { } ctx.User = user } - if post { - mediaParts := strings.Split(ctx.Req.Header.Get("Content-Type"), ";") - if mediaParts[0] != metaMediaType { - writeStatus(ctx, 400) - return false - } - } return true } @@ -71,7 +64,7 @@ func handleLockListOut(ctx *context.Context, repo *models.Repository, lock *mode // GetListLockHandler list locks func GetListLockHandler(ctx *context.Context) { - if !checkIsValidRequest(ctx, false) { + if !checkIsValidRequest(ctx) { return } ctx.Resp.Header().Set("Content-Type", metaMediaType) @@ -135,7 +128,7 @@ func GetListLockHandler(ctx *context.Context) { // PostLockHandler create lock func PostLockHandler(ctx *context.Context) { - if !checkIsValidRequest(ctx, false) { + if !checkIsValidRequest(ctx) { return } ctx.Resp.Header().Set("Content-Type", metaMediaType) @@ -198,7 +191,7 @@ func PostLockHandler(ctx *context.Context) { // VerifyLockHandler list locks for verification func VerifyLockHandler(ctx *context.Context) { - if !checkIsValidRequest(ctx, false) { + if !checkIsValidRequest(ctx) { return } ctx.Resp.Header().Set("Content-Type", metaMediaType) @@ -249,7 +242,7 @@ func VerifyLockHandler(ctx *context.Context) { // UnLockHandler delete locks func UnLockHandler(ctx *context.Context) { - if !checkIsValidRequest(ctx, false) { + if !checkIsValidRequest(ctx) { return } ctx.Resp.Header().Set("Content-Type", metaMediaType) diff --git a/modules/lfs/server.go b/modules/lfs/server.go index 7e20aa851593e..bf5355acfc3b1 100644 --- a/modules/lfs/server.go +++ b/modules/lfs/server.go @@ -152,7 +152,7 @@ func getContentHandler(ctx *context.Context) { if rangeHdr := ctx.Req.Header.Get("Range"); rangeHdr != "" { regex := regexp.MustCompile(`bytes=(\d+)\-.*`) match := regex.FindStringSubmatch(rangeHdr) - if match != nil && len(match) > 1 { + if len(match) > 1 { statusCode = 206 fromByte, _ = strconv.ParseInt(match[1], 10, 32) ctx.Resp.Header().Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", fromByte, meta.Size-1, meta.Size-fromByte)) @@ -178,8 +178,8 @@ func getContentHandler(ctx *context.Context) { } ctx.Resp.WriteHeader(statusCode) - io.Copy(ctx.Resp, content) - content.Close() + _, _ = io.Copy(ctx.Resp, content) + _ = content.Close() logRequest(ctx.Req, statusCode) } @@ -196,7 +196,7 @@ func getMetaHandler(ctx *context.Context) { if ctx.Req.Method == "GET" { enc := json.NewEncoder(ctx.Resp) - enc.Encode(Represent(rv, meta, true, false)) + _ = enc.Encode(Represent(rv, meta, true, false)) } logRequest(ctx.Req, 200) @@ -249,7 +249,7 @@ func PostHandler(ctx *context.Context) { ctx.Resp.WriteHeader(sentStatus) enc := json.NewEncoder(ctx.Resp) - enc.Encode(Represent(rv, meta, meta.Existing, true)) + _ = enc.Encode(Represent(rv, meta, meta.Existing, true)) logRequest(ctx.Req, sentStatus) } @@ -313,7 +313,7 @@ func BatchHandler(ctx *context.Context) { respobj := &BatchResponse{Objects: responseObjects} enc := json.NewEncoder(ctx.Resp) - enc.Encode(respobj) + _ = enc.Encode(respobj) logRequest(ctx.Req, 200) } diff --git a/modules/log/colors.go b/modules/log/colors.go index 0ec8ce4ba86da..c29741634f5e1 100644 --- a/modules/log/colors.go +++ b/modules/log/colors.go @@ -208,7 +208,7 @@ normalLoop: if i > lasti { written, err := c.w.Write(bytes[lasti:i]) - totalWritten = totalWritten + written + totalWritten += written if err != nil { return totalWritten, err } @@ -243,7 +243,7 @@ normalLoop: if bytes[j] == 'm' { if c.mode == allowColor { written, err := c.w.Write(bytes[i : j+1]) - totalWritten = totalWritten + written + totalWritten += written if err != nil { return totalWritten, err } @@ -278,7 +278,7 @@ func ColorSprintf(format string, args ...interface{}) string { } return fmt.Sprintf(format, v...) } - return fmt.Sprintf(format) + return format } // ColorFprintf will write to the provided writer similar to ColorSprintf @@ -290,7 +290,7 @@ func ColorFprintf(w io.Writer, format string, args ...interface{}) (int, error) } return fmt.Fprintf(w, format, v...) } - return fmt.Fprintf(w, format) + return fmt.Fprint(w, format) } // ColorFormatted structs provide their own colored string when formatted with ColorSprintf diff --git a/modules/log/conn.go b/modules/log/conn.go index bd76855168820..88166645265d9 100644 --- a/modules/log/conn.go +++ b/modules/log/conn.go @@ -67,7 +67,10 @@ func (i *connWriter) connect() error { } if tcpConn, ok := conn.(*net.TCPConn); ok { - tcpConn.SetKeepAlive(true) + err = tcpConn.SetKeepAlive(true) + if err != nil { + return err + } } i.innerWriter = conn diff --git a/modules/log/conn_test.go b/modules/log/conn_test.go index 380a115d9636c..cc3d758fa98f9 100644 --- a/modules/log/conn_test.go +++ b/modules/log/conn_test.go @@ -24,7 +24,6 @@ func listenReadAndClose(t *testing.T, l net.Listener, expected string) { assert.NoError(t, err) assert.Equal(t, expected, string(written)) - return } func TestConnLogger(t *testing.T) { diff --git a/modules/log/event.go b/modules/log/event.go index 2ec1f9587d54d..37efa3c2306aa 100644 --- a/modules/log/event.go +++ b/modules/log/event.go @@ -79,7 +79,7 @@ func (l *ChannelledLog) Start() { return } l.loggerProvider.Flush() - case _, _ = <-l.close: + case <-l.close: l.closeLogger() return } @@ -104,7 +104,6 @@ func (l *ChannelledLog) closeLogger() { l.loggerProvider.Flush() l.loggerProvider.Close() l.closed <- true - return } // Close this ChannelledLog @@ -228,7 +227,6 @@ func (m *MultiChannelledLog) closeLoggers() { } m.mutex.Unlock() m.closed <- true - return } // Start processing the MultiChannelledLog diff --git a/modules/log/file.go b/modules/log/file.go index cdda85d626ffa..877820b8bea4e 100644 --- a/modules/log/file.go +++ b/modules/log/file.go @@ -223,7 +223,7 @@ func compressOldLogFile(fname string, compressionLevel int) error { func (log *FileLogger) deleteOldLog() { dir := filepath.Dir(log.Filename) - filepath.Walk(dir, func(path string, info os.FileInfo, err error) (returnErr error) { + _ = filepath.Walk(dir, func(path string, info os.FileInfo, err error) (returnErr error) { defer func() { if r := recover(); r != nil { returnErr = fmt.Errorf("Unable to delete old log '%s', error: %+v", path, r) @@ -246,7 +246,7 @@ func (log *FileLogger) deleteOldLog() { // there are no buffering messages in file logger in memory. // flush file means sync file from disk. func (log *FileLogger) Flush() { - log.mw.fd.Sync() + _ = log.mw.fd.Sync() } // GetName returns the default name for this implementation diff --git a/modules/log/file_test.go b/modules/log/file_test.go index 648db6f393090..38279315ab363 100644 --- a/modules/log/file_test.go +++ b/modules/log/file_test.go @@ -103,7 +103,7 @@ func TestFileLogger(t *testing.T) { assert.Equal(t, expected, string(logData)) event.level = WARN - expected = expected + fmt.Sprintf("%s%s %s:%d:%s [%c] %s\n", prefix, dateString, event.filename, event.line, event.caller, strings.ToUpper(event.level.String())[0], event.msg) + expected += fmt.Sprintf("%s%s %s:%d:%s [%c] %s\n", prefix, dateString, event.filename, event.line, event.caller, strings.ToUpper(event.level.String())[0], event.msg) fileLogger.LogEvent(&event) fileLogger.Flush() logData, err = ioutil.ReadFile(filename) @@ -130,7 +130,7 @@ func TestFileLogger(t *testing.T) { err = realFileLogger.DoRotate() assert.Error(t, err) - expected = expected + fmt.Sprintf("%s%s %s:%d:%s [%c] %s\n", prefix, dateString, event.filename, event.line, event.caller, strings.ToUpper(event.level.String())[0], event.msg) + expected += fmt.Sprintf("%s%s %s:%d:%s [%c] %s\n", prefix, dateString, event.filename, event.line, event.caller, strings.ToUpper(event.level.String())[0], event.msg) fileLogger.LogEvent(&event) fileLogger.Flush() logData, err = ioutil.ReadFile(filename) @@ -138,7 +138,7 @@ func TestFileLogger(t *testing.T) { assert.Equal(t, expected, string(logData)) // Should fail to rotate - expected = expected + fmt.Sprintf("%s%s %s:%d:%s [%c] %s\n", prefix, dateString, event.filename, event.line, event.caller, strings.ToUpper(event.level.String())[0], event.msg) + expected += fmt.Sprintf("%s%s %s:%d:%s [%c] %s\n", prefix, dateString, event.filename, event.line, event.caller, strings.ToUpper(event.level.String())[0], event.msg) fileLogger.LogEvent(&event) fileLogger.Flush() logData, err = ioutil.ReadFile(filename) @@ -188,7 +188,7 @@ func TestCompressFileLogger(t *testing.T) { assert.Equal(t, expected, string(logData)) event.level = WARN - expected = expected + fmt.Sprintf("%s%s %s:%d:%s [%c] %s\n", prefix, dateString, event.filename, event.line, event.caller, strings.ToUpper(event.level.String())[0], event.msg) + expected += fmt.Sprintf("%s%s %s:%d:%s [%c] %s\n", prefix, dateString, event.filename, event.line, event.caller, strings.ToUpper(event.level.String())[0], event.msg) fileLogger.LogEvent(&event) fileLogger.Flush() logData, err = ioutil.ReadFile(filename) diff --git a/modules/log/flags.go b/modules/log/flags.go index 928d42b96546e..992fc62ddb6e8 100644 --- a/modules/log/flags.go +++ b/modules/log/flags.go @@ -57,7 +57,7 @@ func FlagsFromString(from string) int { for _, flag := range strings.Split(strings.ToLower(from), ",") { f, ok := flagFromString[strings.TrimSpace(flag)] if ok { - flags = flags | f + flags |= f } } return flags diff --git a/modules/log/log.go b/modules/log/log.go index 8698e9eed3ae3..0ca0f3adc5af1 100644 --- a/modules/log/log.go +++ b/modules/log/log.go @@ -218,7 +218,7 @@ func (l *LoggerAsWriter) Write(p []byte) (int, error) { func (l *LoggerAsWriter) Log(msg string) { for _, logger := range l.ourLoggers { // Set the skip to reference the call just above this - logger.Log(1, l.level, msg) + _ = logger.Log(1, l.level, msg) } } diff --git a/modules/log/smtp.go b/modules/log/smtp.go index f77d716d9491c..f912299a73628 100644 --- a/modules/log/smtp.go +++ b/modules/log/smtp.go @@ -11,10 +11,6 @@ import ( "strings" ) -const ( - subjectPhrase = "Diagnostic message from server" -) - type smtpWriter struct { owner *SMTPLogger } diff --git a/modules/log/writer.go b/modules/log/writer.go index 22ef0b90476bf..2503f04d76f7e 100644 --- a/modules/log/writer.go +++ b/modules/log/writer.go @@ -252,10 +252,7 @@ func (logger *WriterLogger) Match(event *Event) bool { mode: removeColor, }).Write([]byte(event.msg)) msg = baw - if logger.regexp.Match(msg) { - return true - } - return false + return logger.regexp.Match(msg) } // Close the base logger diff --git a/modules/mailer/mailer.go b/modules/mailer/mailer.go index 411d6eafd8947..d19ae7b2f42ee 100644 --- a/modules/mailer/mailer.go +++ b/modules/mailer/mailer.go @@ -258,15 +258,12 @@ func (s *dummySender) Send(from string, to []string, msg io.WriterTo) error { } func processMailQueue() { - for { - select { - case msg := <-mailQueue: - log.Trace("New e-mail sending request %s: %s", msg.GetHeader("To"), msg.Info) - if err := gomail.Send(Sender, msg.Message); err != nil { - log.Error("Failed to send emails %s: %s - %v", msg.GetHeader("To"), msg.Info, err) - } else { - log.Trace("E-mails sent %s: %s", msg.GetHeader("To"), msg.Info) - } + for msg := range mailQueue { + log.Trace("New e-mail sending request %s: %s", msg.GetHeader("To"), msg.Info) + if err := gomail.Send(Sender, msg.Message); err != nil { + log.Error("Failed to send emails %s: %s - %v", msg.GetHeader("To"), msg.Info, err) + } else { + log.Trace("E-mails sent %s: %s", msg.GetHeader("To"), msg.Info) } } } diff --git a/modules/markup/html.go b/modules/markup/html.go index 91913b06792ac..dbfc8dbe85f71 100644 --- a/modules/markup/html.go +++ b/modules/markup/html.go @@ -108,24 +108,6 @@ func FindAllMentions(content string) []string { return ret } -// cutoutVerbosePrefix cutouts URL prefix including sub-path to -// return a clean unified string of request URL path. -func cutoutVerbosePrefix(prefix string) string { - if len(prefix) == 0 || prefix[0] != '/' { - return prefix - } - count := 0 - for i := 0; i < len(prefix); i++ { - if prefix[i] == '/' { - count++ - } - if count >= 3+setting.AppSubURLDepth { - return prefix[:i] - } - } - return prefix -} - // IsSameDomain checks if given url string has the same hostname as current Gitea instance func IsSameDomain(s string) bool { if strings.HasPrefix(s, "/") { @@ -146,7 +128,7 @@ type postProcessError struct { } func (p *postProcessError) Error() string { - return "PostProcess: " + p.context + ", " + p.Error() + return "PostProcess: " + p.context + ", " + p.err.Error() } type processor func(ctx *postProcessCtx, node *html.Node) @@ -304,20 +286,6 @@ func (ctx *postProcessCtx) visitNode(node *html.Node) { // ignore everything else } -func (ctx *postProcessCtx) visitNodeForShortLinks(node *html.Node) { - switch node.Type { - case html.TextNode: - shortLinkProcessorFull(ctx, node, true) - case html.ElementNode: - if node.Data == "code" || node.Data == "pre" || node.Data == "a" { - return - } - for n := node.FirstChild; n != nil; n = n.NextSibling { - ctx.visitNodeForShortLinks(n) - } - } -} - // textNode runs the passed node through various processors, in order to handle // all kinds of special links handled by the post-processing. func (ctx *postProcessCtx) textNode(node *html.Node) { diff --git a/modules/markup/html_internal_test.go b/modules/markup/html_internal_test.go index 135a8e103c573..10bc4973cd525 100644 --- a/modules/markup/html_internal_test.go +++ b/modules/markup/html_internal_test.go @@ -29,11 +29,6 @@ func numericIssueLink(baseURL string, index int) string { return link(util.URLJoin(baseURL, strconv.Itoa(index)), fmt.Sprintf("#%d", index)) } -// urlContentsLink an HTML link whose contents is the target URL -func urlContentsLink(href string) string { - return link(href, href) -} - // link an HTML link func link(href, contents string) string { return fmt.Sprintf("%s", href, contents) diff --git a/modules/notification/mail/mail.go b/modules/notification/mail/mail.go index 9689f4d4ab54b..9d0db4f415197 100644 --- a/modules/notification/mail/mail.go +++ b/modules/notification/mail/mail.go @@ -42,7 +42,7 @@ func (m *mailNotifier) NotifyCreateIssueComment(doer *models.User, repo *models. } func (m *mailNotifier) NotifyNewIssue(issue *models.Issue) { - if err := issue.MailParticipants(models.ActionCreateIssue); err != nil { + if err := issue.MailParticipants(issue.Poster, models.ActionCreateIssue); err != nil { log.Error("MailParticipants: %v", err) } } @@ -63,13 +63,13 @@ func (m *mailNotifier) NotifyIssueChangeStatus(doer *models.User, issue *models. } } - if err := issue.MailParticipants(actionType); err != nil { + if err := issue.MailParticipants(doer, actionType); err != nil { log.Error("MailParticipants: %v", err) } } func (m *mailNotifier) NotifyNewPullRequest(pr *models.PullRequest) { - if err := pr.Issue.MailParticipants(models.ActionCreatePullRequest); err != nil { + if err := pr.Issue.MailParticipants(pr.Issue.Poster, models.ActionCreatePullRequest); err != nil { log.Error("MailParticipants: %v", err) } } diff --git a/modules/notification/ui/ui.go b/modules/notification/ui/ui.go index a31591c2a708d..22089158f5b72 100644 --- a/modules/notification/ui/ui.go +++ b/modules/notification/ui/ui.go @@ -35,12 +35,9 @@ func NewNotifier() base.Notifier { } func (ns *notificationService) Run() { - for { - select { - case opts := <-ns.issueQueue: - if err := models.CreateOrUpdateIssueNotifications(opts.issue, opts.notificationAuthorID); err != nil { - log.Error("Was unable to create issue notification: %v", err) - } + for opts := range ns.issueQueue { + if err := models.CreateOrUpdateIssueNotifications(opts.issue, opts.notificationAuthorID); err != nil { + log.Error("Was unable to create issue notification: %v", err) } } } diff --git a/modules/pprof/pprof.go b/modules/pprof/pprof.go index b63904e713626..80ad67be3a81b 100644 --- a/modules/pprof/pprof.go +++ b/modules/pprof/pprof.go @@ -9,6 +9,8 @@ import ( "io/ioutil" "runtime" "runtime/pprof" + + "code.gitea.io/gitea/modules/log" ) // DumpMemProfileForUsername dumps a memory profile at pprofDataPath as memprofile_POST
запросы на указанный URL адрес, с информацией о происходящих событиях. Подробности на странице инструкции по использованию webhooks.
settings.payload_url=URL обработчика
+settings.http_method=Метод HTTP
settings.content_type=Тип содержимого
settings.secret=Секретный ключ
settings.slack_username=Имя пользователя
@@ -1145,6 +1201,8 @@ settings.slack_domain=Домен
settings.slack_channel=Канал
settings.add_discord_hook_desc=Добавить уведомления о событиях через Discord.
settings.add_dingtalk_hook_desc=Добавить интеграцию с Dingtalk в ваш репозиторий.
+settings.add_telegram_hook_desc=Добавить интеграцию с Telegram в ваш репозиторий.
+settings.add_msteams_hook_desc=Добавить интеграцию с Microsoft Teams в ваш репозиторий.
settings.deploy_keys=Ключи развертывания
settings.add_deploy_key=Добавить ключ развертывания
settings.deploy_key_desc=Ключи развёртывания доступны только для чтения. Это не то же самое что и SSH-ключи аккаунта.
@@ -1166,7 +1224,9 @@ settings.protected_branch_can_push_yes=Вы можете выполнять push
settings.protected_branch_can_push_no=Вы не можете выполнять push
settings.branch_protection=Защита ветки %s
settings.protect_this_branch=Защитить эту ветку
+settings.protect_this_branch_desc=Запретить push в ветку и защитить от удаления.
settings.protect_whitelist_committers=Белый список тех, кто может делать push в эту ветку
+settings.protect_whitelist_committers_desc=Разрешить push в эту ветку пользователям или командам из «белого» списка (но не принудительный push).
settings.protect_whitelist_users=Пользователи, которые могут делать push в эту ветку:
settings.protect_whitelist_search_users=Поиск пользователей…
settings.protect_whitelist_teams=Команды, члены которых могут делать push в эту ветку:
@@ -1190,6 +1250,8 @@ settings.choose_branch=Выберите ветку…
settings.no_protected_branch=Нет защищённых веток.
settings.edit_protected_branch=Редактировать
settings.protected_branch_required_approvals_min=Число необходимых одобрений не может быть отрицательным.
+settings.bot_token=Токен для бота
+settings.chat_id=ID чата
settings.archive.button=Архивировать репозиторий
settings.archive.header=Архивировать этот репозиторий
settings.archive.text=Архивация репозитория переведет его в режим read-only. Он будет скрыт из панели управления, создание задач, запросов на слияние, или создание коммитов будут запрещены.
@@ -1198,7 +1260,7 @@ settings.archive.error_ismirror=Вы не можете поместить зер
settings.unarchive.button=Разархивировать
settings.unarchive.header=Разархивировать этот репозиторий
settings.unarchive.success=Репозиторий был успешно разархивирован.
-settings.unarchive.error=Ошибка при попытке разархивировать репозиторий. Смотрите логи для получения подробностей.
+settings.update_avatar_success=Аватар репозитория обновлен.
diff.browse_source=Просмотр исходного кода
diff.parent=Родитель
diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini
index 5ac415460d721..6b495bee87388 100644
--- a/options/locale/locale_zh-CN.ini
+++ b/options/locale/locale_zh-CN.ini
@@ -86,12 +86,18 @@ host=数据库主机
user=用户名
password=数据库用户密码
db_name=数据库名称
+db_helper=MySQL 用户注意:请使用InnoDB 存储引擎,如果您使用“utf8mb4”,您的 InnoDB 版本必须大于5.6。
ssl_mode=SSL
+charset=字符集
path=数据库文件路径
sqlite_helper=SQLite3 数据库的文件路径。{{RenderCommitBody .Commit.Message $.RepoLink $.Repository.ComposeMetas}}+ {{end}} + {{.BranchName}} +
{{RenderNote .Note $.RepoLink $.Repository.ComposeMetas}}+
{{RenderCommitBody .Commit.Message $.RepoLink $.Repository.ComposeMetas}}- {{end}} - {{.BranchName}} -
{{RenderNote .Note $.RepoLink $.Repository.ComposeMetas}}-