diff --git a/integrations/api_packages_generic_test.go b/integrations/api_packages_generic_test.go
index adaf99e981ae..c60a387f533b 100644
--- a/integrations/api_packages_generic_test.go
+++ b/integrations/api_packages_generic_test.go
@@ -23,16 +23,16 @@ func TestPackageGeneric(t *testing.T) {
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
packageName := "te-st_pac.kage"
- packageVersion := "1.0.3"
+ packageVersion := "1.0.3-te st"
filename := "fi-le_na.me"
content := []byte{1, 2, 3}
- url := fmt.Sprintf("/api/packages/%s/generic/%s/%s/%s", user.Name, packageName, packageVersion, filename)
+ url := fmt.Sprintf("/api/packages/%s/generic/%s/%s", user.Name, packageName, packageVersion)
t.Run("Upload", func(t *testing.T) {
defer PrintCurrentTest(t)()
- req := NewRequestWithBody(t, "PUT", url, bytes.NewReader(content))
+ req := NewRequestWithBody(t, "PUT", url+"/"+filename, bytes.NewReader(content))
AddBasicAuthHeader(req, user.Name)
MakeRequest(t, req, http.StatusCreated)
@@ -55,54 +55,139 @@ func TestPackageGeneric(t *testing.T) {
pb, err := packages.GetBlobByID(db.DefaultContext, pfs[0].BlobID)
assert.NoError(t, err)
assert.Equal(t, int64(len(content)), pb.Size)
- })
- t.Run("UploadExists", func(t *testing.T) {
- defer PrintCurrentTest(t)()
+ t.Run("Exists", func(t *testing.T) {
+ defer PrintCurrentTest(t)()
- req := NewRequestWithBody(t, "PUT", url, bytes.NewReader(content))
- AddBasicAuthHeader(req, user.Name)
- MakeRequest(t, req, http.StatusBadRequest)
+ req := NewRequestWithBody(t, "PUT", url+"/"+filename, bytes.NewReader(content))
+ AddBasicAuthHeader(req, user.Name)
+ MakeRequest(t, req, http.StatusConflict)
+ })
+
+ t.Run("Additional", func(t *testing.T) {
+ defer PrintCurrentTest(t)()
+
+ req := NewRequestWithBody(t, "PUT", url+"/dummy.bin", bytes.NewReader(content))
+ AddBasicAuthHeader(req, user.Name)
+ MakeRequest(t, req, http.StatusCreated)
+
+ // Check deduplication
+ pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
+ assert.NoError(t, err)
+ assert.Len(t, pfs, 2)
+ assert.Equal(t, pfs[0].BlobID, pfs[1].BlobID)
+ })
+
+ t.Run("InvalidParameter", func(t *testing.T) {
+ defer PrintCurrentTest(t)()
+
+ req := NewRequestWithBody(t, "PUT", fmt.Sprintf("/api/packages/%s/generic/%s/%s/%s", user.Name, "invalid+package name", packageVersion, filename), bytes.NewReader(content))
+ AddBasicAuthHeader(req, user.Name)
+ MakeRequest(t, req, http.StatusBadRequest)
+
+ req = NewRequestWithBody(t, "PUT", fmt.Sprintf("/api/packages/%s/generic/%s/%s/%s", user.Name, packageName, "%20test ", filename), bytes.NewReader(content))
+ AddBasicAuthHeader(req, user.Name)
+ MakeRequest(t, req, http.StatusBadRequest)
+
+ req = NewRequestWithBody(t, "PUT", fmt.Sprintf("/api/packages/%s/generic/%s/%s/%s", user.Name, packageName, packageVersion, "inval+id.na me"), bytes.NewReader(content))
+ AddBasicAuthHeader(req, user.Name)
+ MakeRequest(t, req, http.StatusBadRequest)
+ })
})
t.Run("Download", func(t *testing.T) {
defer PrintCurrentTest(t)()
- req := NewRequest(t, "GET", url)
+ checkDownloadCount := func(count int64) {
+ pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeGeneric)
+ assert.NoError(t, err)
+ assert.Len(t, pvs, 1)
+ assert.Equal(t, count, pvs[0].DownloadCount)
+ }
+
+ checkDownloadCount(0)
+
+ req := NewRequest(t, "GET", url+"/"+filename)
resp := MakeRequest(t, req, http.StatusOK)
assert.Equal(t, content, resp.Body.Bytes())
- pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeGeneric)
- assert.NoError(t, err)
- assert.Len(t, pvs, 1)
- assert.Equal(t, int64(1), pvs[0].DownloadCount)
+ checkDownloadCount(1)
+
+ req = NewRequest(t, "GET", url+"/dummy.bin")
+ MakeRequest(t, req, http.StatusOK)
+
+ checkDownloadCount(2)
+
+ t.Run("NotExists", func(t *testing.T) {
+ defer PrintCurrentTest(t)()
+
+ req := NewRequest(t, "GET", url+"/not.found")
+ MakeRequest(t, req, http.StatusNotFound)
+ })
})
t.Run("Delete", func(t *testing.T) {
defer PrintCurrentTest(t)()
- req := NewRequest(t, "DELETE", url)
- AddBasicAuthHeader(req, user.Name)
- MakeRequest(t, req, http.StatusOK)
+ t.Run("File", func(t *testing.T) {
+ defer PrintCurrentTest(t)()
- pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeGeneric)
- assert.NoError(t, err)
- assert.Empty(t, pvs)
- })
+ req := NewRequest(t, "DELETE", url+"/"+filename)
+ MakeRequest(t, req, http.StatusUnauthorized)
- t.Run("DownloadNotExists", func(t *testing.T) {
- defer PrintCurrentTest(t)()
+ req = NewRequest(t, "DELETE", url+"/"+filename)
+ AddBasicAuthHeader(req, user.Name)
+ MakeRequest(t, req, http.StatusNoContent)
- req := NewRequest(t, "GET", url)
- MakeRequest(t, req, http.StatusNotFound)
- })
+ req = NewRequest(t, "GET", url+"/"+filename)
+ MakeRequest(t, req, http.StatusNotFound)
- t.Run("DeleteNotExists", func(t *testing.T) {
- defer PrintCurrentTest(t)()
+ req = NewRequest(t, "DELETE", url+"/"+filename)
+ AddBasicAuthHeader(req, user.Name)
+ MakeRequest(t, req, http.StatusNotFound)
- req := NewRequest(t, "DELETE", url)
- AddBasicAuthHeader(req, user.Name)
- MakeRequest(t, req, http.StatusNotFound)
+ pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeGeneric)
+ assert.NoError(t, err)
+ assert.Len(t, pvs, 1)
+
+ t.Run("RemovesVersion", func(t *testing.T) {
+ defer PrintCurrentTest(t)()
+
+ req = NewRequest(t, "DELETE", url+"/dummy.bin")
+ AddBasicAuthHeader(req, user.Name)
+ MakeRequest(t, req, http.StatusNoContent)
+
+ pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeGeneric)
+ assert.NoError(t, err)
+ assert.Empty(t, pvs)
+ })
+ })
+
+ t.Run("Version", func(t *testing.T) {
+ defer PrintCurrentTest(t)()
+
+ req := NewRequestWithBody(t, "PUT", url+"/"+filename, bytes.NewReader(content))
+ AddBasicAuthHeader(req, user.Name)
+ MakeRequest(t, req, http.StatusCreated)
+
+ req = NewRequest(t, "DELETE", url)
+ MakeRequest(t, req, http.StatusUnauthorized)
+
+ req = NewRequest(t, "DELETE", url)
+ AddBasicAuthHeader(req, user.Name)
+ MakeRequest(t, req, http.StatusNoContent)
+
+ pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeGeneric)
+ assert.NoError(t, err)
+ assert.Empty(t, pvs)
+
+ req = NewRequest(t, "GET", url+"/"+filename)
+ MakeRequest(t, req, http.StatusNotFound)
+
+ req = NewRequest(t, "DELETE", url)
+ AddBasicAuthHeader(req, user.Name)
+ MakeRequest(t, req, http.StatusNotFound)
+ })
})
}
diff --git a/integrations/api_packages_npm_test.go b/integrations/api_packages_npm_test.go
index ad88ac5da676..23f13866bf50 100644
--- a/integrations/api_packages_npm_test.go
+++ b/integrations/api_packages_npm_test.go
@@ -36,33 +36,36 @@ func TestPackageNpm(t *testing.T) {
packageDescription := "Test Description"
data := "H4sIAAAAAAAA/ytITM5OTE/VL4DQelnF+XkMVAYGBgZmJiYK2MRBwNDcSIHB2NTMwNDQzMwAqA7IMDUxA9LUdgg2UFpcklgEdAql5kD8ogCnhwio5lJQUMpLzE1VslJQcihOzi9I1S9JLS7RhSYIJR2QgrLUouLM/DyQGkM9Az1D3YIiqExKanFyUWZBCVQ2BKhVwQVJDKwosbQkI78IJO/tZ+LsbRykxFXLNdA+HwWjYBSMgpENACgAbtAACAAA"
- upload := `{
- "_id": "` + packageName + `",
- "name": "` + packageName + `",
- "description": "` + packageDescription + `",
- "dist-tags": {
- "` + packageTag + `": "` + packageVersion + `"
- },
- "versions": {
- "` + packageVersion + `": {
+
+ buildUpload := func(version string) string {
+ return `{
+ "_id": "` + packageName + `",
"name": "` + packageName + `",
- "version": "` + packageVersion + `",
"description": "` + packageDescription + `",
- "author": {
- "name": "` + packageAuthor + `"
+ "dist-tags": {
+ "` + packageTag + `": "` + version + `"
+ },
+ "versions": {
+ "` + version + `": {
+ "name": "` + packageName + `",
+ "version": "` + version + `",
+ "description": "` + packageDescription + `",
+ "author": {
+ "name": "` + packageAuthor + `"
+ },
+ "dist": {
+ "integrity": "sha512-yA4FJsVhetynGfOC1jFf79BuS+jrHbm0fhh+aHzCQkOaOBXKf9oBnC4a6DnLLnEsHQDRLYd00cwj8sCXpC+wIg==",
+ "shasum": "aaa7eaf852a948b0aa05afeda35b1badca155d90"
+ }
+ }
},
- "dist": {
- "integrity": "sha512-yA4FJsVhetynGfOC1jFf79BuS+jrHbm0fhh+aHzCQkOaOBXKf9oBnC4a6DnLLnEsHQDRLYd00cwj8sCXpC+wIg==",
- "shasum": "aaa7eaf852a948b0aa05afeda35b1badca155d90"
+ "_attachments": {
+ "` + packageName + `-` + version + `.tgz": {
+ "data": "` + data + `"
+ }
}
- }
- },
- "_attachments": {
- "` + packageName + `-` + packageVersion + `.tgz": {
- "data": "` + data + `"
- }
- }
- }`
+ }`
+ }
root := fmt.Sprintf("/api/packages/%s/npm/%s", user.Name, url.QueryEscape(packageName))
tagsRoot := fmt.Sprintf("/api/packages/%s/npm/-/package/%s/dist-tags", user.Name, url.QueryEscape(packageName))
@@ -71,7 +74,7 @@ func TestPackageNpm(t *testing.T) {
t.Run("Upload", func(t *testing.T) {
defer PrintCurrentTest(t)()
- req := NewRequestWithBody(t, "PUT", root, strings.NewReader(upload))
+ req := NewRequestWithBody(t, "PUT", root, strings.NewReader(buildUpload(packageVersion)))
req = addTokenAuthHeader(req, token)
MakeRequest(t, req, http.StatusCreated)
@@ -103,7 +106,7 @@ func TestPackageNpm(t *testing.T) {
t.Run("UploadExists", func(t *testing.T) {
defer PrintCurrentTest(t)()
- req := NewRequestWithBody(t, "PUT", root, strings.NewReader(upload))
+ req := NewRequestWithBody(t, "PUT", root, strings.NewReader(buildUpload(packageVersion)))
req = addTokenAuthHeader(req, token)
MakeRequest(t, req, http.StatusBadRequest)
})
@@ -219,4 +222,57 @@ func TestPackageNpm(t *testing.T) {
test(t, http.StatusOK, "dummy")
test(t, http.StatusOK, packageTag2)
})
+
+ t.Run("Delete", func(t *testing.T) {
+ defer PrintCurrentTest(t)()
+
+ req := NewRequestWithBody(t, "PUT", root, strings.NewReader(buildUpload(packageVersion+"-dummy")))
+ req = addTokenAuthHeader(req, token)
+ MakeRequest(t, req, http.StatusCreated)
+
+ req = NewRequest(t, "PUT", root+"/-rev/dummy")
+ MakeRequest(t, req, http.StatusUnauthorized)
+
+ req = NewRequest(t, "PUT", root+"/-rev/dummy")
+ req = addTokenAuthHeader(req, token)
+ MakeRequest(t, req, http.StatusOK)
+
+ t.Run("Version", func(t *testing.T) {
+ defer PrintCurrentTest(t)()
+
+ pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeNpm)
+ assert.NoError(t, err)
+ assert.Len(t, pvs, 2)
+
+ req := NewRequest(t, "DELETE", fmt.Sprintf("%s/-/%s/%s/-rev/dummy", root, packageVersion, filename))
+ MakeRequest(t, req, http.StatusUnauthorized)
+
+ req = NewRequest(t, "DELETE", fmt.Sprintf("%s/-/%s/%s/-rev/dummy", root, packageVersion, filename))
+ req = addTokenAuthHeader(req, token)
+ MakeRequest(t, req, http.StatusOK)
+
+ pvs, err = packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeNpm)
+ assert.NoError(t, err)
+ assert.Len(t, pvs, 1)
+ })
+
+ t.Run("Full", func(t *testing.T) {
+ defer PrintCurrentTest(t)()
+
+ pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeNpm)
+ assert.NoError(t, err)
+ assert.Len(t, pvs, 1)
+
+ req := NewRequest(t, "DELETE", root+"/-rev/dummy")
+ MakeRequest(t, req, http.StatusUnauthorized)
+
+ req = NewRequest(t, "DELETE", root+"/-rev/dummy")
+ req = addTokenAuthHeader(req, token)
+ MakeRequest(t, req, http.StatusOK)
+
+ pvs, err = packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeNpm)
+ assert.NoError(t, err)
+ assert.Len(t, pvs, 0)
+ })
+ })
}
diff --git a/integrations/git_test.go b/integrations/git_test.go
index d6bd673822ba..f9e1eafb6583 100644
--- a/integrations/git_test.go
+++ b/integrations/git_test.go
@@ -156,11 +156,6 @@ func standardCommitAndPushTest(t *testing.T, dstPath string) (little, big string
func lfsCommitAndPushTest(t *testing.T, dstPath string) (littleLFS, bigLFS string) {
t.Run("LFS", func(t *testing.T) {
defer PrintCurrentTest(t)()
- git.CheckLFSVersion()
- if !setting.LFS.StartServer {
- t.Skip()
- return
- }
prefix := "lfs-data-file-"
err := git.NewCommand(git.DefaultContext, "lfs").AddArguments("install").Run(&git.RunOpts{Dir: dstPath})
assert.NoError(t, err)
@@ -226,7 +221,6 @@ func rawTest(t *testing.T, ctx *APITestContext, little, big, littleLFS, bigLFS s
resp := session.MakeRequestNilResponseRecorder(t, req, http.StatusOK)
assert.Equal(t, littleSize, resp.Length)
- git.CheckLFSVersion()
if setting.LFS.StartServer {
req = NewRequest(t, "GET", path.Join("/", username, reponame, "/raw/branch/master/", littleLFS))
resp := session.MakeRequest(t, req, http.StatusOK)
@@ -268,12 +262,9 @@ func mediaTest(t *testing.T, ctx *APITestContext, little, big, littleLFS, bigLFS
resp := session.MakeRequestNilResponseRecorder(t, req, http.StatusOK)
assert.Equal(t, littleSize, resp.Length)
- git.CheckLFSVersion()
- if setting.LFS.StartServer {
- req = NewRequest(t, "GET", path.Join("/", username, reponame, "/media/branch/master/", littleLFS))
- resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK)
- assert.Equal(t, littleSize, resp.Length)
- }
+ req = NewRequest(t, "GET", path.Join("/", username, reponame, "/media/branch/master/", littleLFS))
+ resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK)
+ assert.Equal(t, littleSize, resp.Length)
if !testing.Short() {
req = NewRequest(t, "GET", path.Join("/", username, reponame, "/media/branch/master/", big))
diff --git a/integrations/integration_test.go b/integrations/integration_test.go
index 230f780175c9..3c379f5c84ef 100644
--- a/integrations/integration_test.go
+++ b/integrations/integration_test.go
@@ -175,10 +175,9 @@ func initIntegrationTest() {
setting.Repository.DefaultBranch = "master" // many test code still assume that default branch is called "master"
_ = util.RemoveAll(repo_module.LocalCopyPath())
- if err := git.InitOnceWithSync(context.Background()); err != nil {
+ if err := git.InitFull(context.Background()); err != nil {
log.Fatal("git.InitOnceWithSync: %v", err)
}
- git.CheckLFSVersion()
setting.InitDBConfig()
if err := storage.Init(); err != nil {
@@ -285,7 +284,6 @@ func prepareTestEnv(t testing.TB, skip ...int) func() {
assert.NoError(t, unittest.LoadFixtures())
assert.NoError(t, util.RemoveAll(setting.RepoRootPath))
assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), setting.RepoRootPath))
- assert.NoError(t, git.InitOnceWithSync(context.Background())) // the gitconfig has been removed above, so sync the gitconfig again
ownerDirs, err := os.ReadDir(setting.RepoRootPath)
if err != nil {
assert.NoError(t, err, "unable to read the new repo root: %v\n", err)
@@ -586,7 +584,6 @@ func resetFixtures(t *testing.T) {
assert.NoError(t, unittest.LoadFixtures())
assert.NoError(t, util.RemoveAll(setting.RepoRootPath))
assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), setting.RepoRootPath))
- assert.NoError(t, git.InitOnceWithSync(context.Background())) // the gitconfig has been removed above, so sync the gitconfig again
ownerDirs, err := os.ReadDir(setting.RepoRootPath)
if err != nil {
assert.NoError(t, err, "unable to read the new repo root: %v\n", err)
diff --git a/integrations/lfs_getobject_test.go b/integrations/lfs_getobject_test.go
index 4b6bb140d3ad..14a8ac253e2c 100644
--- a/integrations/lfs_getobject_test.go
+++ b/integrations/lfs_getobject_test.go
@@ -14,7 +14,6 @@ import (
git_model "code.gitea.io/gitea/models/git"
repo_model "code.gitea.io/gitea/models/repo"
- "code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/lfs"
"code.gitea.io/gitea/modules/setting"
@@ -83,11 +82,6 @@ func checkResponseTestContentEncoding(t *testing.T, content *[]byte, resp *httpt
func TestGetLFSSmall(t *testing.T) {
defer prepareTestEnv(t)()
- git.CheckLFSVersion()
- if !setting.LFS.StartServer {
- t.Skip()
- return
- }
content := []byte("A very small file\n")
resp := storeAndGetLfs(t, &content, nil, http.StatusOK)
@@ -96,11 +90,6 @@ func TestGetLFSSmall(t *testing.T) {
func TestGetLFSLarge(t *testing.T) {
defer prepareTestEnv(t)()
- git.CheckLFSVersion()
- if !setting.LFS.StartServer {
- t.Skip()
- return
- }
content := make([]byte, web.GzipMinSize*10)
for i := range content {
content[i] = byte(i % 256)
@@ -112,11 +101,6 @@ func TestGetLFSLarge(t *testing.T) {
func TestGetLFSGzip(t *testing.T) {
defer prepareTestEnv(t)()
- git.CheckLFSVersion()
- if !setting.LFS.StartServer {
- t.Skip()
- return
- }
b := make([]byte, web.GzipMinSize*10)
for i := range b {
b[i] = byte(i % 256)
@@ -133,11 +117,6 @@ func TestGetLFSGzip(t *testing.T) {
func TestGetLFSZip(t *testing.T) {
defer prepareTestEnv(t)()
- git.CheckLFSVersion()
- if !setting.LFS.StartServer {
- t.Skip()
- return
- }
b := make([]byte, web.GzipMinSize*10)
for i := range b {
b[i] = byte(i % 256)
@@ -156,11 +135,6 @@ func TestGetLFSZip(t *testing.T) {
func TestGetLFSRangeNo(t *testing.T) {
defer prepareTestEnv(t)()
- git.CheckLFSVersion()
- if !setting.LFS.StartServer {
- t.Skip()
- return
- }
content := []byte("123456789\n")
resp := storeAndGetLfs(t, &content, nil, http.StatusOK)
@@ -169,11 +143,6 @@ func TestGetLFSRangeNo(t *testing.T) {
func TestGetLFSRange(t *testing.T) {
defer prepareTestEnv(t)()
- git.CheckLFSVersion()
- if !setting.LFS.StartServer {
- t.Skip()
- return
- }
content := []byte("123456789\n")
tests := []struct {
diff --git a/integrations/migration-test/migration_test.go b/integrations/migration-test/migration_test.go
index 20a5c903a92c..80093d66f1ed 100644
--- a/integrations/migration-test/migration_test.go
+++ b/integrations/migration-test/migration_test.go
@@ -82,8 +82,7 @@ func initMigrationTest(t *testing.T) func() {
}
}
- assert.NoError(t, git.InitOnceWithSync(context.Background()))
- git.CheckLFSVersion()
+ assert.NoError(t, git.InitFull(context.Background()))
setting.InitDBConfig()
setting.NewLogServices(true)
return deferFn
diff --git a/models/migrations/migrations_test.go b/models/migrations/migrations_test.go
index 46782f24a100..53e4f3539564 100644
--- a/models/migrations/migrations_test.go
+++ b/models/migrations/migrations_test.go
@@ -66,11 +66,10 @@ func TestMain(m *testing.M) {
setting.SetCustomPathAndConf("", "", "")
setting.LoadForTest()
- if err = git.InitOnceWithSync(context.Background()); err != nil {
- fmt.Printf("Unable to InitOnceWithSync: %v\n", err)
+ if err = git.InitFull(context.Background()); err != nil {
+ fmt.Printf("Unable to InitFull: %v\n", err)
os.Exit(1)
}
- git.CheckLFSVersion()
setting.InitDBConfig()
setting.NewLogServices(true)
@@ -207,7 +206,6 @@ func prepareTestEnv(t *testing.T, skip int, syncModels ...interface{}) (*xorm.En
deferFn := PrintCurrentTest(t, ourSkip)
assert.NoError(t, os.RemoveAll(setting.RepoRootPath))
assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), setting.RepoRootPath))
- assert.NoError(t, git.InitOnceWithSync(context.Background())) // the gitconfig has been removed above, so sync the gitconfig again
ownerDirs, err := os.ReadDir(setting.RepoRootPath)
if err != nil {
assert.NoError(t, err, "unable to read the new repo root: %v\n", err)
diff --git a/models/repo/user_repo.go b/models/repo/user_repo.go
index 71e0c57550c5..6c0a241dc562 100644
--- a/models/repo/user_repo.go
+++ b/models/repo/user_repo.go
@@ -170,3 +170,15 @@ func GetReviewers(ctx context.Context, repo *Repository, doerID, posterID int64)
users := make([]*user_model.User, 0, 8)
return users, db.GetEngine(ctx).Where(cond).OrderBy(user_model.GetOrderByName()).Find(&users)
}
+
+// GetIssuePosters returns all users that have authored an issue/pull request for the given repository
+func GetIssuePosters(ctx context.Context, repo *Repository, isPull bool) ([]*user_model.User, error) {
+ users := make([]*user_model.User, 0, 8)
+ cond := builder.In("`user`.id",
+ builder.Select("poster_id").From("issue").Where(
+ builder.Eq{"repo_id": repo.ID}.
+ And(builder.Eq{"is_pull": isPull}),
+ ).GroupBy("poster_id"),
+ )
+ return users, db.GetEngine(ctx).Where(cond).OrderBy(user_model.GetOrderByName()).Find(&users)
+}
diff --git a/models/unittest/testdb.go b/models/unittest/testdb.go
index 7f9af553747c..58656f781f13 100644
--- a/models/unittest/testdb.go
+++ b/models/unittest/testdb.go
@@ -120,11 +120,9 @@ func MainTest(m *testing.M, testOpts *TestOptions) {
fatalTestError("util.CopyDir: %v\n", err)
}
- if err = git.InitOnceWithSync(context.Background()); err != nil {
+ if err = git.InitFull(context.Background()); err != nil {
fatalTestError("git.Init: %v\n", err)
}
- git.CheckLFSVersion()
-
ownerDirs, err := os.ReadDir(setting.RepoRootPath)
if err != nil {
fatalTestError("unable to read the new repo root: %v\n", err)
@@ -206,8 +204,6 @@ func PrepareTestEnv(t testing.TB) {
assert.NoError(t, util.RemoveAll(setting.RepoRootPath))
metaPath := filepath.Join(giteaRoot, "integrations", "gitea-repositories-meta")
assert.NoError(t, CopyDir(metaPath, setting.RepoRootPath))
- assert.NoError(t, git.InitOnceWithSync(context.Background())) // the gitconfig has been removed above, so sync the gitconfig again
-
ownerDirs, err := os.ReadDir(setting.RepoRootPath)
assert.NoError(t, err)
for _, ownerDir := range ownerDirs {
diff --git a/modules/context/context.go b/modules/context/context.go
index 882491161992..0b9898acef04 100644
--- a/modules/context/context.go
+++ b/modules/context/context.go
@@ -224,7 +224,7 @@ func (ctx *Context) HTML(status int, name base.TplName) {
ctx.Data["TemplateLoadTimes"] = func() string {
return strconv.FormatInt(time.Since(tmplStartTime).Nanoseconds()/1e6, 10) + "ms"
}
- if err := ctx.Render.HTML(ctx.Resp, status, string(name), ctx.Data); err != nil {
+ if err := ctx.Render.HTML(ctx.Resp, status, string(name), templates.BaseVars().Merge(ctx.Data)); err != nil {
if status == http.StatusInternalServerError && name == base.TplName("status/500") {
ctx.PlainText(http.StatusInternalServerError, "Unable to find status/500 template")
return
diff --git a/modules/doctor/mergebase.go b/modules/doctor/mergebase.go
index 2da91cdcc35f..46369290a13d 100644
--- a/modules/doctor/mergebase.go
+++ b/modules/doctor/mergebase.go
@@ -30,9 +30,6 @@ func iteratePRs(ctx context.Context, repo *repo_model.Repository, each func(*rep
}
func checkPRMergeBase(ctx context.Context, logger log.Logger, autofix bool) error {
- if err := git.InitOnceWithSync(ctx); err != nil {
- return err
- }
numRepos := 0
numPRs := 0
numPRsUpdated := 0
diff --git a/modules/doctor/misc.go b/modules/doctor/misc.go
index 24175fcaf4be..2d2bcb910db4 100644
--- a/modules/doctor/misc.go
+++ b/modules/doctor/misc.go
@@ -190,10 +190,6 @@ func checkDaemonExport(ctx context.Context, logger log.Logger, autofix bool) err
}
func checkCommitGraph(ctx context.Context, logger log.Logger, autofix bool) error {
- if err := git.InitOnceWithSync(ctx); err != nil {
- return err
- }
-
numRepos := 0
numNeedUpdate := 0
numWritten := 0
diff --git a/modules/git/git.go b/modules/git/git.go
index b8317396c015..99849f1f0945 100644
--- a/modules/git/git.go
+++ b/modules/git/git.go
@@ -15,7 +15,6 @@ import (
"regexp"
"runtime"
"strings"
- "sync"
"time"
"code.gitea.io/gitea/modules/log"
@@ -24,8 +23,8 @@ import (
"github.com/hashicorp/go-version"
)
-// GitVersionRequired is the minimum Git version required
-const GitVersionRequired = "2.0.0"
+// RequiredVersion is the minimum Git version required
+const RequiredVersion = "2.0.0"
var (
// GitExecutable is the command name of git
@@ -43,7 +42,7 @@ var (
// loadGitVersion returns current Git version from shell. Internal usage only.
func loadGitVersion() (*version.Version, error) {
- // doesn't need RWMutex because its exec by Init()
+ // doesn't need RWMutex because it's executed by Init()
if gitVersion != nil {
return gitVersion, nil
}
@@ -90,7 +89,7 @@ func SetExecutablePath(path string) error {
return fmt.Errorf("unable to load git version: %w", err)
}
- versionRequired, err := version.NewVersion(GitVersionRequired)
+ versionRequired, err := version.NewVersion(RequiredVersion)
if err != nil {
return err
}
@@ -104,7 +103,7 @@ func SetExecutablePath(path string) error {
moreHint = "get git: https://git-scm.com/download/linux and https://ius.io"
}
}
- return fmt.Errorf("installed git version %q is not supported, Gitea requires git version >= %q, %s", gitVersion.Original(), GitVersionRequired, moreHint)
+ return fmt.Errorf("installed git version %q is not supported, Gitea requires git version >= %q, %s", gitVersion.Original(), RequiredVersion, moreHint)
}
return nil
@@ -131,7 +130,7 @@ func checkInit() error {
return errors.New("unable to init Git's HomeDir, incorrect initialization of the setting and git modules")
}
if DefaultContext != nil {
- log.Warn("git module has been initialized already, duplicate init should be fixed")
+ log.Warn("git module has been initialized already, duplicate init may work but it's better to fix it")
}
return nil
}
@@ -140,7 +139,7 @@ func checkInit() error {
func HomeDir() string {
if setting.Git.HomePath == "" {
// strict check, make sure the git module is initialized correctly.
- // attention: when the git module is called in gitea sub-command (serv/hook), the log module is not able to show messages to users.
+ // attention: when the git module is called in gitea sub-command (serv/hook), the log module might not obviously show messages to users/developers.
// for example: if there is gitea git hook code calling git.NewCommand before git.InitXxx, the integration test won't show the real failure reasons.
log.Fatal("Unable to init Git's HomeDir, incorrect initialization of the setting and git modules")
return ""
@@ -149,14 +148,14 @@ func HomeDir() string {
}
// InitSimple initializes git module with a very simple step, no config changes, no global command arguments.
-// This method doesn't change anything to filesystem. At the moment, it is only used by "git serv" sub-command, no data-race
-// However, in integration test, the sub-command function may be called in the current process, so the InitSimple would be called multiple times, too
+// This method doesn't change anything to filesystem. At the moment, it is only used by some Gitea sub-commands.
func InitSimple(ctx context.Context) error {
if err := checkInit(); err != nil {
return err
}
DefaultContext = ctx
+ globalCommandArgs = nil
if setting.Git.Timeout.Default > 0 {
defaultCommandExecutionTimeout = time.Duration(setting.Git.Timeout.Default) * time.Second
@@ -165,46 +164,46 @@ func InitSimple(ctx context.Context) error {
return SetExecutablePath(setting.Git.Path)
}
-var initOnce sync.Once
-
-// InitOnceWithSync initializes git module with version check and change global variables, sync gitconfig.
-// This method will update the global variables ONLY ONCE (just like git.CheckLFSVersion -- which is not ideal too),
-// otherwise there will be data-race problem at the moment.
-func InitOnceWithSync(ctx context.Context) (err error) {
+// InitFull initializes git module with version check and change global variables, sync gitconfig.
+// It should only be called once at the beginning of the program initialization (TestMain/GlobalInitInstalled) as this code makes unsynchronized changes to variables.
+func InitFull(ctx context.Context) (err error) {
if err = checkInit(); err != nil {
return err
}
- initOnce.Do(func() {
- if err = InitSimple(ctx); err != nil {
- return
- }
+ if err = InitSimple(ctx); err != nil {
+ return
+ }
- // when git works with gnupg (commit signing), there should be a stable home for gnupg commands
- if _, ok := os.LookupEnv("GNUPGHOME"); !ok {
- _ = os.Setenv("GNUPGHOME", filepath.Join(HomeDir(), ".gnupg"))
- }
+ // when git works with gnupg (commit signing), there should be a stable home for gnupg commands
+ if _, ok := os.LookupEnv("GNUPGHOME"); !ok {
+ _ = os.Setenv("GNUPGHOME", filepath.Join(HomeDir(), ".gnupg"))
+ }
- // Since git wire protocol has been released from git v2.18
- if setting.Git.EnableAutoGitWireProtocol && CheckGitVersionAtLeast("2.18") == nil {
- globalCommandArgs = append(globalCommandArgs, "-c", "protocol.version=2")
- }
+ // Since git wire protocol has been released from git v2.18
+ if setting.Git.EnableAutoGitWireProtocol && CheckGitVersionAtLeast("2.18") == nil {
+ globalCommandArgs = append(globalCommandArgs, "-c", "protocol.version=2")
+ }
- // By default partial clones are disabled, enable them from git v2.22
- if !setting.Git.DisablePartialClone && CheckGitVersionAtLeast("2.22") == nil {
- globalCommandArgs = append(globalCommandArgs, "-c", "uploadpack.allowfilter=true", "-c", "uploadpack.allowAnySHA1InWant=true")
- }
+ // By default partial clones are disabled, enable them from git v2.22
+ if !setting.Git.DisablePartialClone && CheckGitVersionAtLeast("2.22") == nil {
+ globalCommandArgs = append(globalCommandArgs, "-c", "uploadpack.allowfilter=true", "-c", "uploadpack.allowAnySHA1InWant=true")
+ }
- // Explicitly disable credential helper, otherwise Git credentials might leak
- if CheckGitVersionAtLeast("2.9") == nil {
- globalCommandArgs = append(globalCommandArgs, "-c", "credential.helper=")
- }
+ // Explicitly disable credential helper, otherwise Git credentials might leak
+ if CheckGitVersionAtLeast("2.9") == nil {
+ globalCommandArgs = append(globalCommandArgs, "-c", "credential.helper=")
+ }
- SupportProcReceive = CheckGitVersionAtLeast("2.29") == nil
- })
- if err != nil {
- return err
+ SupportProcReceive = CheckGitVersionAtLeast("2.29") == nil
+
+ if setting.LFS.StartServer {
+ if CheckGitVersionAtLeast("2.1.2") != nil {
+ return errors.New("LFS server support requires Git >= 2.1.2")
+ }
+ globalCommandArgs = append(globalCommandArgs, "-c", "filter.lfs.required=", "-c", "filter.lfs.smudge=", "-c", "filter.lfs.clean=")
}
+
return syncGitConfig()
}
diff --git a/modules/git/git_test.go b/modules/git/git_test.go
index c5a63de0644c..091573787871 100644
--- a/modules/git/git_test.go
+++ b/modules/git/git_test.go
@@ -28,7 +28,7 @@ func testRun(m *testing.M) error {
defer util.RemoveAll(gitHomePath)
setting.Git.HomePath = gitHomePath
- if err = InitOnceWithSync(context.Background()); err != nil {
+ if err = InitFull(context.Background()); err != nil {
return fmt.Errorf("failed to call Init: %w", err)
}
diff --git a/modules/git/lfs.go b/modules/git/lfs.go
deleted file mode 100644
index c5d8354b6dc8..000000000000
--- a/modules/git/lfs.go
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2021 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 (
- "sync"
-
- logger "code.gitea.io/gitea/modules/log"
- "code.gitea.io/gitea/modules/setting"
-)
-
-var once sync.Once
-
-// CheckLFSVersion will check lfs version, if not satisfied, then disable it.
-func CheckLFSVersion() {
- if setting.LFS.StartServer {
- // Disable LFS client hooks if installed for the current OS user
- // Needs at least git v2.1.2
- if CheckGitVersionAtLeast("2.1.2") != nil {
- setting.LFS.StartServer = false
- logger.Error("LFS server support needs at least Git v2.1.2")
- } else {
- once.Do(func() {
- globalCommandArgs = append(globalCommandArgs, "-c", "filter.lfs.required=",
- "-c", "filter.lfs.smudge=", "-c", "filter.lfs.clean=")
- })
- }
- }
-}
diff --git a/modules/util/sec_to_time.go b/modules/util/sec_to_time.go
index 9ce6fe1a13eb..13461915e6f3 100644
--- a/modules/util/sec_to_time.go
+++ b/modules/util/sec_to_time.go
@@ -18,10 +18,22 @@ import (
// 45677465s -> 1 year 6 months
func SecToTime(duration int64) string {
formattedTime := ""
- years := duration / (3600 * 24 * 7 * 4 * 12)
- months := (duration / (3600 * 24 * 30)) % 12
- weeks := (duration / (3600 * 24 * 7)) % 4
- days := (duration / (3600 * 24)) % 7
+
+ // The following four variables are calculated by taking
+ // into account the previously calculated variables, this avoids
+ // pitfalls when using remainders. As that could lead to incorrect
+ // results when the calculated number equals the quotient number.
+ remainingDays := duration / (60 * 60 * 24)
+ years := remainingDays / 365
+ remainingDays -= years * 365
+ months := remainingDays * 12 / 365
+ remainingDays -= months * 365 / 12
+ weeks := remainingDays / 7
+ remainingDays -= weeks * 7
+ days := remainingDays
+
+ // The following three variables are calculated without depending
+ // on the previous calculated variables.
hours := (duration / 3600) % 24
minutes := (duration / 60) % 60
seconds := duration % 60
diff --git a/modules/util/sec_to_time_test.go b/modules/util/sec_to_time_test.go
index 854190462bc3..1e256aa8650c 100644
--- a/modules/util/sec_to_time_test.go
+++ b/modules/util/sec_to_time_test.go
@@ -11,10 +11,21 @@ import (
)
func TestSecToTime(t *testing.T) {
- assert.Equal(t, SecToTime(66), "1 minute 6 seconds")
- assert.Equal(t, SecToTime(52410), "14 hours 33 minutes")
- assert.Equal(t, SecToTime(563418), "6 days 12 hours")
- assert.Equal(t, SecToTime(1563418), "2 weeks 4 days")
- assert.Equal(t, SecToTime(3937125), "1 month 2 weeks")
- assert.Equal(t, SecToTime(45677465), "1 year 5 months")
+ second := int64(1)
+ minute := 60 * second
+ hour := 60 * minute
+ day := 24 * hour
+ year := 365 * day
+
+ assert.Equal(t, "1 minute 6 seconds", SecToTime(minute+6*second))
+ assert.Equal(t, "1 hour", SecToTime(hour))
+ assert.Equal(t, "1 hour", SecToTime(hour+second))
+ assert.Equal(t, "14 hours 33 minutes", SecToTime(14*hour+33*minute+30*second))
+ assert.Equal(t, "6 days 12 hours", SecToTime(6*day+12*hour+30*minute+18*second))
+ assert.Equal(t, "2 weeks 4 days", SecToTime((2*7+4)*day+2*hour+16*minute+58*second))
+ assert.Equal(t, "4 weeks", SecToTime(4*7*day))
+ assert.Equal(t, "4 weeks 1 day", SecToTime((4*7+1)*day))
+ assert.Equal(t, "1 month 2 weeks", SecToTime((6*7+3)*day+13*hour+38*minute+45*second))
+ assert.Equal(t, "11 months", SecToTime(year-25*day))
+ assert.Equal(t, "1 year 5 months", SecToTime(year+163*day+10*hour+11*minute+5*second))
}
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index 783783617b6a..426521e4ee21 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -1269,6 +1269,8 @@ issues.filter_milestone = Milestone
issues.filter_milestone_no_select = All milestones
issues.filter_assignee = Assignee
issues.filter_assginee_no_select = All assignees
+issues.filter_poster = Author
+issues.filter_poster_no_select = All authors
issues.filter_type = Type
issues.filter_type.all_issues = All issues
issues.filter_type.assigned_to_you = Assigned to you
diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini
index 15222272b334..be3c2fbb34bf 100644
--- a/options/locale/locale_es-ES.ini
+++ b/options/locale/locale_es-ES.ini
@@ -179,6 +179,8 @@ log_root_path_helper=Archivos de registro se escribirán en este directorio.
optional_title=Configuración opcional
email_title=Configuración de Correo
+smtp_addr=Servidor SMTP
+smtp_port=Puerto SMTP
smtp_from=Enviar correos electrónicos como
smtp_from_helper=Dirección de correo electrónico que utilizará Gitea. Introduzca una dirección de correo electrónico normal o utilice el formato "Nombre"
.
mailer_user=Nombre de usuario SMTP
@@ -1061,6 +1063,7 @@ normal_view=Vista normal
line=línea
lines=líneas
+editor.add_file=Añadir archivo
editor.new_file=Nuevo Archivo
editor.upload_file=Subir archivo
editor.edit_file=Editar Archivo
@@ -2794,13 +2797,19 @@ config.queue_length=Tamaño de Cola de Envío
config.deliver_timeout=Timeout de Entrega
config.skip_tls_verify=Saltar verificación TLS
+config.mailer_config=Configuración del servidor de correo
config.mailer_enabled=Activado
+config.mailer_enable_helo=Habilitar HELO
config.mailer_name=Nombre
+config.mailer_protocol=Protocolo
+config.mailer_smtp_addr=Dirección SMTP
+config.mailer_smtp_port=Puerto SMTP
config.mailer_user=Usuario
config.mailer_use_sendmail=Usar Sendmail
config.mailer_sendmail_path=Ruta de Sendmail
config.mailer_sendmail_args=Argumentos adicionales por Sendmail
config.mailer_sendmail_timeout=Tiempo de espera de Sendmail
+config.mailer_use_dummy=Dummy
config.test_email_placeholder=Correo electrónico (ej. test@ejemplo.com)
config.send_test_mail=Enviar prueba de correo
config.test_mail_failed=Fallo al enviar correo electrónico de prueba a '%s': %v
@@ -3103,6 +3112,10 @@ npm.dependencies.development=Dependencias de desarrollo
npm.dependencies.peer=Dependencias de pares
npm.dependencies.optional=Dependencias opcionales
npm.details.tag=Etiqueta
+pub.install=Para instalar el paquete usando Dart, ejecute el siguiente comando:
+pub.documentation=Para obtener más información sobre el registro de Pub, consulte la documentación.
+pub.details.repository_site=Sitio del repositorio
+pub.details.documentation_site=Sitio de documentación
pypi.requires=Requiere Python
pypi.install=Para instalar el paquete usando pip, ejecute el siguiente comando:
pypi.documentation=Para obtener más información sobre el registro PyPI, consulte la documentación.
diff --git a/options/locale/locale_fi-FI.ini b/options/locale/locale_fi-FI.ini
index 4f47d8afa64a..0323854339b5 100644
--- a/options/locale/locale_fi-FI.ini
+++ b/options/locale/locale_fi-FI.ini
@@ -664,6 +664,7 @@ visibility_helper=Tee reposta yksityinen
fork_repo=Forkkaa repo
fork_from=Forkkaa lähteestä
fork_visibility_helper=Forkatun repon näkyvyyttä ei voi muuttaa.
+clone_in_vsc=Kloonaa VS Codessa
download_zip=Lataa ZIP
download_tar=Lataa TAR.GZ
repo_desc=Kuvaus
@@ -801,14 +802,27 @@ commits.ssh_key_fingerprint=SSH avaimen sormenjälki
+projects=Projektit
projects.description_placeholder=Kuvaus
projects.create=Luo projekti
projects.title=Otsikko
projects.new=Uusi projekti
+projects.create_success=Projekti '%s' on luotu.
projects.deletion=Poista projekti
+projects.deletion_success=Projekti on poistettu.
+projects.edit=Muokkaa projektia
+projects.modify=Päivitä projekti
+projects.edit_success=Projekti '%s' on päivitetty.
projects.type.basic_kanban=Yksinkertainen Kanban
+projects.type.uncategorized=Luokittelematon
+projects.board.edit=Muokkaa luetteloa
+projects.board.new_submit=Lähetä
projects.board.new=Uusi taulu
+projects.board.set_default=Aseta oletukseksi
projects.board.delete=Poista taulu
+projects.board.color=Väri
+projects.open=Avaa
+projects.close=Sulje
issues.desc=Ongelmien, tehtävien ja merkkipaalujen hallinta.
issues.filter_milestones=Suodata merkkipaalu
@@ -1110,11 +1124,22 @@ settings.event_repository=Repo
settings.event_issue_comment_desc=Ongelman kommentti luotu, muokattu tai poistettu.
settings.event_pull_request=Vetopyyntö
settings.update_webhook=Päivitä webkoukku
+settings.delete_webhook=Poista webkoukku
settings.recent_deliveries=Viimeisimmät toimitukset
settings.hook_type=Koukkutyyppi
settings.slack_token=Pääsymerkki
settings.slack_domain=Verkkotunnus
settings.slack_channel=Kanava
+settings.web_hook_name_gitea=Gitea
+settings.web_hook_name_gogs=Gogs
+settings.web_hook_name_slack=Slack
+settings.web_hook_name_discord=Discord
+settings.web_hook_name_dingtalk=DingTalk
+settings.web_hook_name_telegram=Telegram
+settings.web_hook_name_matrix=Matrix
+settings.web_hook_name_feishu=Feishu
+settings.web_hook_name_larksuite=Lark Suite
+settings.web_hook_name_packagist=Packagist
settings.deploy_keys=Deploy avaimet
settings.add_deploy_key=Lisää deploy avain
settings.title=Otsikko
@@ -1141,6 +1166,7 @@ settings.tags=Tagit
settings.tags.protection.pattern=Tagin kuvio
settings.tags.protection.pattern.description=Voit käyttää yhtä nimeä tai glob-kuviota tai säännöllistä lauseketta, joka täsmää useisiin tageihin. Lue lisää suojatut tagit oppaasta.
settings.bot_token=Botti pääsymerkki
+settings.matrix.homeserver_url=Kotipalvelimen URL
settings.matrix.access_token=Pääsymerkki
settings.archive.button=Arkistoi repo
settings.archive.header=Arkistoi tämä repo
@@ -1390,6 +1416,7 @@ repos.forks=Haarat
repos.issues=Ongelmat
repos.size=Koko
+packages.owner=Omistaja
diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini
index ac7da8dd1760..acc2fad7e833 100644
--- a/options/locale/locale_lv-LV.ini
+++ b/options/locale/locale_lv-LV.ini
@@ -1063,6 +1063,7 @@ normal_view=Parastais skats
line=rinda
lines=rindas
+editor.add_file=Pievienot
editor.new_file=Jauna datne
editor.upload_file=Augšupielādēt failu
editor.edit_file=Labot failu
@@ -3111,6 +3112,10 @@ npm.dependencies.development=Izstrādes atkarības
npm.dependencies.peer=Netiešās atkarības
npm.dependencies.optional=Neobligātās atkarības
npm.details.tag=Tags
+pub.install=Lai instalētu Dart pakotni, izpildiet sekojošu komandu:
+pub.documentation=Papildus informācija par Pub reģistru pieejama dokumentācijā.
+pub.details.repository_site=Repozitorija izmērs
+pub.details.documentation_site=Dokumentācijas lapa
pypi.requires=Nepieciešams Python
pypi.install=Lai instalētu pip pakotni, izpildiet sekojošu komandu:
pypi.documentation=Papildus informācija par PyPI reģistru pieejama dokumentācijā.
diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini
index 50b92a95c58b..b0bb9e1b16cc 100644
--- a/options/locale/locale_pt-PT.ini
+++ b/options/locale/locale_pt-PT.ini
@@ -1063,6 +1063,7 @@ normal_view=Vista normal
line=linha
lines=linhas
+editor.add_file=Adicionar ficheiro
editor.new_file=Novo ficheiro
editor.upload_file=Carregar ficheiro
editor.edit_file=Editar ficheiro
@@ -3111,6 +3112,10 @@ npm.dependencies.development=Dependências de desenvolvimento
npm.dependencies.peer=Dependências de pares
npm.dependencies.optional=Dependências opcionais
npm.details.tag=Etiqueta
+pub.install=Para instalar o pacote usando o Dart, execute o seguinte comando:
+pub.documentation=Para obter mais informações sobre o registo Pub, consulte a documentação.
+pub.details.repository_site=Página web do repositório
+pub.details.documentation_site=Página web da documentação
pypi.requires=Requer Python
pypi.install=Para instalar o pacote usando o pip, execute o seguinte comando:
pypi.documentation=Para obter mais informações sobre o registo do PyPI, consulte a documentação.
diff --git a/options/locale/locale_tr-TR.ini b/options/locale/locale_tr-TR.ini
index 07565395cdbd..d33713c684f3 100644
--- a/options/locale/locale_tr-TR.ini
+++ b/options/locale/locale_tr-TR.ini
@@ -1063,6 +1063,7 @@ normal_view=Normal Görünüm
line=satır
lines=satır
+editor.add_file=Dosya Ekle
editor.new_file=Yeni dosya
editor.upload_file=Dosya Yükle
editor.edit_file=Dosyayı Düzenle
@@ -3111,6 +3112,10 @@ npm.dependencies.development=Geliştirme Bağımlılıkları
npm.dependencies.peer=Eş Bağımlılıkları
npm.dependencies.optional=İsteğe Bağlı Bağımlılıklar
npm.details.tag=Etiket
+pub.install=Paketi Dart ile kurmak için, şu komutu çalıştırın:
+pub.documentation=Pub kütüğü hakkında daha fazla bilgi için, belgeye bakabilirsiniz.
+pub.details.repository_site=Depo Sitesi
+pub.details.documentation_site=Belge Sitesi
pypi.requires=Gereken Python
pypi.install=Paketi pip ile kurmak için, şu komutu çalıştırın:
pypi.documentation=PyPI kütüğü hakkında daha fazla bilgi için, belgeye bakabilirsiniz.
diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini
index ef239d0e3fbf..5d8e427a9125 100644
--- a/options/locale/locale_zh-CN.ini
+++ b/options/locale/locale_zh-CN.ini
@@ -9,7 +9,7 @@ sign_out=退出
sign_up=注册
link_account=链接账户
register=注册
-website=官方网站
+website=网站
version=当前版本
powered_by=Powered by %s
page=页面
@@ -20,7 +20,7 @@ active_stopwatch=活动时间跟踪器
create_new=创建…
user_profile_and_more=个人信息和配置
signed_in_as=已登录用户
-enable_javascript=使用 JavaScript能使本网站更好的工作。
+enable_javascript=使用 JavaScript 能使本网站更好的工作。
toc=目录
licenses=许可证
return_to_gitea=返回 Gitea
@@ -2203,7 +2203,7 @@ release.stable=稳定
release.compare=比较
release.edit=编辑
release.ahead.commits=%d 次提交
-release.ahead.target=到 %s 自发布后
+release.ahead.target=在此版本发布后被加入到 %s
release.source_code=源代码
release.new_subheader=版本发布组织项目的版本。
release.edit_subheader=版本发布组织项目的版本。
@@ -2314,7 +2314,7 @@ form.create_org_not_allowed=此账号禁止创建组织
settings=组织设置
settings.options=组织
settings.full_name=组织全名
-settings.website=官方网站
+settings.website=网站
settings.location=所在地区
settings.permission=权限
settings.repoadminchangeteam=仓库管理员可以添加或移除团队的访问权限
diff --git a/routers/api/packages/api.go b/routers/api/packages/api.go
index 4b274860dcdf..39ba41cdfbf1 100644
--- a/routers/api/packages/api.go
+++ b/routers/api/packages/api.go
@@ -156,12 +156,15 @@ func Routes() *web.Route {
})
})
r.Group("/generic", func() {
- r.Group("/{packagename}/{packageversion}/{filename}", func() {
- r.Get("", generic.DownloadPackageFile)
- r.Group("", func() {
- r.Put("", generic.UploadPackage)
- r.Delete("", generic.DeletePackage)
- }, reqPackageAccess(perm.AccessModeWrite))
+ r.Group("/{packagename}/{packageversion}", func() {
+ r.Delete("", reqPackageAccess(perm.AccessModeWrite), generic.DeletePackage)
+ r.Group("/{filename}", func() {
+ r.Get("", generic.DownloadPackageFile)
+ r.Group("", func() {
+ r.Put("", generic.UploadPackage)
+ r.Delete("", generic.DeletePackageFile)
+ }, reqPackageAccess(perm.AccessModeWrite))
+ })
})
})
r.Group("/helm", func() {
@@ -195,12 +198,26 @@ func Routes() *web.Route {
r.Group("/@{scope}/{id}", func() {
r.Get("", npm.PackageMetadata)
r.Put("", reqPackageAccess(perm.AccessModeWrite), npm.UploadPackage)
- r.Get("/-/{version}/{filename}", npm.DownloadPackageFile)
+ r.Group("/-/{version}/{filename}", func() {
+ r.Get("", npm.DownloadPackageFile)
+ r.Delete("/-rev/{revision}", reqPackageAccess(perm.AccessModeWrite), npm.DeletePackageVersion)
+ })
+ r.Group("/-rev/{revision}", func() {
+ r.Delete("", npm.DeletePackage)
+ r.Put("", npm.DeletePreview)
+ }, reqPackageAccess(perm.AccessModeWrite))
})
r.Group("/{id}", func() {
r.Get("", npm.PackageMetadata)
r.Put("", reqPackageAccess(perm.AccessModeWrite), npm.UploadPackage)
- r.Get("/-/{version}/{filename}", npm.DownloadPackageFile)
+ r.Group("/-/{version}/{filename}", func() {
+ r.Get("", npm.DownloadPackageFile)
+ r.Delete("/-rev/{revision}", reqPackageAccess(perm.AccessModeWrite), npm.DeletePackageVersion)
+ })
+ r.Group("/-rev/{revision}", func() {
+ r.Delete("", npm.DeletePackage)
+ r.Put("", npm.DeletePreview)
+ }, reqPackageAccess(perm.AccessModeWrite))
})
r.Group("/-/package/@{scope}/{id}/dist-tags", func() {
r.Get("", npm.ListPackageTags)
diff --git a/routers/api/packages/generic/generic.go b/routers/api/packages/generic/generic.go
index 9a3a185d9da5..79e5afb03cae 100644
--- a/routers/api/packages/generic/generic.go
+++ b/routers/api/packages/generic/generic.go
@@ -31,22 +31,16 @@ func apiError(ctx *context.Context, status int, obj interface{}) {
// DownloadPackageFile serves the specific generic package.
func DownloadPackageFile(ctx *context.Context) {
- packageName, packageVersion, filename, err := sanitizeParameters(ctx)
- if err != nil {
- apiError(ctx, http.StatusBadRequest, err)
- return
- }
-
s, pf, err := packages_service.GetFileStreamByPackageNameAndVersion(
ctx,
&packages_service.PackageInfo{
Owner: ctx.Package.Owner,
PackageType: packages_model.TypeGeneric,
- Name: packageName,
- Version: packageVersion,
+ Name: ctx.Params("packagename"),
+ Version: ctx.Params("packageversion"),
},
&packages_service.PackageFileInfo{
- Filename: filename,
+ Filename: ctx.Params("filename"),
},
)
if err != nil {
@@ -65,9 +59,17 @@ func DownloadPackageFile(ctx *context.Context) {
// UploadPackage uploads the specific generic package.
// Duplicated packages get rejected.
func UploadPackage(ctx *context.Context) {
- packageName, packageVersion, filename, err := sanitizeParameters(ctx)
- if err != nil {
- apiError(ctx, http.StatusBadRequest, err)
+ packageName := ctx.Params("packagename")
+ filename := ctx.Params("filename")
+
+ if !packageNameRegex.MatchString(packageName) || !filenameRegex.MatchString(filename) {
+ apiError(ctx, http.StatusBadRequest, errors.New("Invalid package name or filename"))
+ return
+ }
+
+ packageVersion := ctx.Params("packageversion")
+ if packageVersion != strings.TrimSpace(packageVersion) {
+ apiError(ctx, http.StatusBadRequest, errors.New("Invalid package version"))
return
}
@@ -88,7 +90,7 @@ func UploadPackage(ctx *context.Context) {
}
defer buf.Close()
- _, _, err = packages_service.CreatePackageAndAddFile(
+ _, _, err = packages_service.CreatePackageOrAddFileToExisting(
&packages_service.PackageCreationInfo{
PackageInfo: packages_service.PackageInfo{
Owner: ctx.Package.Owner,
@@ -107,8 +109,8 @@ func UploadPackage(ctx *context.Context) {
},
)
if err != nil {
- if err == packages_model.ErrDuplicatePackageVersion {
- apiError(ctx, http.StatusBadRequest, err)
+ if err == packages_model.ErrDuplicatePackageFile {
+ apiError(ctx, http.StatusConflict, err)
return
}
apiError(ctx, http.StatusInternalServerError, err)
@@ -120,19 +122,13 @@ func UploadPackage(ctx *context.Context) {
// DeletePackage deletes the specific generic package.
func DeletePackage(ctx *context.Context) {
- packageName, packageVersion, _, err := sanitizeParameters(ctx)
- if err != nil {
- apiError(ctx, http.StatusBadRequest, err)
- return
- }
-
- err = packages_service.RemovePackageVersionByNameAndVersion(
+ err := packages_service.RemovePackageVersionByNameAndVersion(
ctx.Doer,
&packages_service.PackageInfo{
Owner: ctx.Package.Owner,
PackageType: packages_model.TypeGeneric,
- Name: packageName,
- Version: packageVersion,
+ Name: ctx.Params("packagename"),
+ Version: ctx.Params("packageversion"),
},
)
if err != nil {
@@ -144,21 +140,50 @@ func DeletePackage(ctx *context.Context) {
return
}
- ctx.Status(http.StatusOK)
+ ctx.Status(http.StatusNoContent)
}
-func sanitizeParameters(ctx *context.Context) (string, string, string, error) {
- packageName := ctx.Params("packagename")
- filename := ctx.Params("filename")
+// DeletePackageFile deletes the specific file of a generic package.
+func DeletePackageFile(ctx *context.Context) {
+ pv, pf, err := func() (*packages_model.PackageVersion, *packages_model.PackageFile, error) {
+ pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypeGeneric, ctx.Params("packagename"), ctx.Params("packageversion"))
+ if err != nil {
+ return nil, nil, err
+ }
- if !packageNameRegex.MatchString(packageName) || !filenameRegex.MatchString(filename) {
- return "", "", "", errors.New("Invalid package name or filename")
+ pf, err := packages_model.GetFileForVersionByName(ctx, pv.ID, ctx.Params("filename"), packages_model.EmptyFileKey)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ return pv, pf, nil
+ }()
+ if err != nil {
+ if err == packages_model.ErrPackageNotExist || err == packages_model.ErrPackageFileNotExist {
+ apiError(ctx, http.StatusNotFound, err)
+ return
+ }
+ apiError(ctx, http.StatusInternalServerError, err)
+ return
}
- packageVersion := strings.TrimSpace(ctx.Params("packageversion"))
- if packageVersion == "" {
- return "", "", "", errors.New("Invalid package version")
+ pfs, err := packages_model.GetFilesByVersionID(ctx, pv.ID)
+ if err != nil {
+ apiError(ctx, http.StatusInternalServerError, err)
+ return
+ }
+
+ if len(pfs) == 1 {
+ if err := packages_service.RemovePackageVersion(ctx.Doer, pv); err != nil {
+ apiError(ctx, http.StatusInternalServerError, err)
+ return
+ }
+ } else {
+ if err := packages_service.DeletePackageFile(ctx, pf); err != nil {
+ apiError(ctx, http.StatusInternalServerError, err)
+ return
+ }
}
- return packageName, packageVersion, filename, nil
+ ctx.Status(http.StatusNoContent)
}
diff --git a/routers/api/packages/npm/npm.go b/routers/api/packages/npm/npm.go
index 152edc681a04..d5ba70f9645b 100644
--- a/routers/api/packages/npm/npm.go
+++ b/routers/api/packages/npm/npm.go
@@ -164,6 +164,63 @@ func UploadPackage(ctx *context.Context) {
ctx.Status(http.StatusCreated)
}
+// DeletePreview does nothing
+// The client tells the server what package version it knows about after deleting a version.
+func DeletePreview(ctx *context.Context) {
+ ctx.Status(http.StatusOK)
+}
+
+// DeletePackageVersion deletes the package version
+func DeletePackageVersion(ctx *context.Context) {
+ packageName := packageNameFromParams(ctx)
+ packageVersion := ctx.Params("version")
+
+ err := packages_service.RemovePackageVersionByNameAndVersion(
+ ctx.Doer,
+ &packages_service.PackageInfo{
+ Owner: ctx.Package.Owner,
+ PackageType: packages_model.TypeNpm,
+ Name: packageName,
+ Version: packageVersion,
+ },
+ )
+ if err != nil {
+ if err == packages_model.ErrPackageNotExist {
+ apiError(ctx, http.StatusNotFound, err)
+ return
+ }
+ apiError(ctx, http.StatusInternalServerError, err)
+ return
+ }
+
+ ctx.Status(http.StatusOK)
+}
+
+// DeletePackage deletes the package and all versions
+func DeletePackage(ctx *context.Context) {
+ packageName := packageNameFromParams(ctx)
+
+ pvs, err := packages_model.GetVersionsByPackageName(ctx, ctx.Package.Owner.ID, packages_model.TypeNpm, packageName)
+ if err != nil {
+ apiError(ctx, http.StatusInternalServerError, err)
+ return
+ }
+
+ if len(pvs) == 0 {
+ apiError(ctx, http.StatusNotFound, err)
+ return
+ }
+
+ for _, pv := range pvs {
+ if err := packages_service.RemovePackageVersion(ctx.Doer, pv); err != nil {
+ apiError(ctx, http.StatusInternalServerError, err)
+ return
+ }
+ }
+
+ ctx.Status(http.StatusOK)
+}
+
// ListPackageTags returns all tags for a package
func ListPackageTags(ctx *context.Context) {
packageName := packageNameFromParams(ctx)
diff --git a/routers/init.go b/routers/init.go
index e640ca48453b..612fc5a83dbb 100644
--- a/routers/init.go
+++ b/routers/init.go
@@ -100,10 +100,8 @@ func GlobalInitInstalled(ctx context.Context) {
log.Fatal("Gitea is not installed")
}
- mustInitCtx(ctx, git.InitOnceWithSync)
+ mustInitCtx(ctx, git.InitFull)
log.Info("Git Version: %s (home: %s)", git.VersionInfo(), git.HomeDir())
-
- git.CheckLFSVersion()
log.Info("AppPath: %s", setting.AppPath)
log.Info("AppWorkPath: %s", setting.AppWorkPath)
log.Info("Custom path: %s", setting.CustomPath)
diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go
index e6f9529e31e8..ad25a94e13b1 100644
--- a/routers/web/repo/issue.go
+++ b/routers/web/repo/issue.go
@@ -133,7 +133,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
var (
assigneeID = ctx.FormInt64("assignee")
- posterID int64
+ posterID = ctx.FormInt64("poster")
mentionedID int64
reviewRequestedID int64
forceEmpty bool
@@ -291,6 +291,12 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
return
}
+ ctx.Data["Posters"], err = repo_model.GetIssuePosters(ctx, repo, isPullOption.IsTrue())
+ if err != nil {
+ ctx.ServerError("GetIssuePosters", err)
+ return
+ }
+
handleTeamMentions(ctx)
if ctx.Written() {
return
@@ -364,6 +370,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
ctx.Data["SortType"] = sortType
ctx.Data["MilestoneID"] = milestoneID
ctx.Data["AssigneeID"] = assigneeID
+ ctx.Data["PosterID"] = posterID
ctx.Data["IsShowClosed"] = isShowClosed
ctx.Data["Keyword"] = keyword
if isShowClosed {
@@ -379,6 +386,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
pager.AddParam(ctx, "labels", "SelectLabels")
pager.AddParam(ctx, "milestone", "MilestoneID")
pager.AddParam(ctx, "assignee", "AssigneeID")
+ pager.AddParam(ctx, "poster", "PosterID")
ctx.Data["Page"] = pager
}
diff --git a/routers/web/web.go b/routers/web/web.go
index a9f43fb2c4fe..34d3de6fde0a 100644
--- a/routers/web/web.go
+++ b/routers/web/web.go
@@ -22,7 +22,6 @@ import (
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/storage"
"code.gitea.io/gitea/modules/structs"
- "code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/modules/validation"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/modules/web/routing"
@@ -43,7 +42,6 @@ import (
context_service "code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/forms"
"code.gitea.io/gitea/services/lfs"
- "code.gitea.io/gitea/services/mailer"
_ "code.gitea.io/gitea/modules/session" // to registers all internal adapters
@@ -152,8 +150,6 @@ func Routes() *web.Route {
common = append(common, h)
}
- mailer.InitMailRender(templates.Mailer())
-
if setting.Service.EnableCaptcha {
// The captcha http.Handler should only fire on /captcha/* so we can just mount this on that url
routes.Route("/captcha/*", "GET,HEAD", append(common, captcha.Captchaer(context.GetImageCaptcha()))...)
diff --git a/services/auth/source/oauth2/jwtsigningkey.go b/services/auth/source/oauth2/jwtsigningkey.go
index 24f2c41119c1..d6b3c05a4fcb 100644
--- a/services/auth/source/oauth2/jwtsigningkey.go
+++ b/services/auth/source/oauth2/jwtsigningkey.go
@@ -31,11 +31,11 @@ import (
// ErrInvalidAlgorithmType represents an invalid algorithm error.
type ErrInvalidAlgorithmType struct {
- Algorightm string
+ Algorithm string
}
func (err ErrInvalidAlgorithmType) Error() string {
- return fmt.Sprintf("JWT signing algorithm is not supported: %s", err.Algorightm)
+ return fmt.Sprintf("JWT signing algorithm is not supported: %s", err.Algorithm)
}
// JWTSigningKey represents a algorithm/key pair to sign JWTs
diff --git a/services/mailer/mail.go b/services/mailer/mail.go
index b8d79bd818a0..738a207ce8d0 100644
--- a/services/mailer/mail.go
+++ b/services/mailer/mail.go
@@ -55,12 +55,6 @@ var (
subjectRemoveSpaces = regexp.MustCompile(`[\s]+`)
)
-// InitMailRender initializes the mail renderer
-func InitMailRender(subjectTpl *texttmpl.Template, bodyTpl *template.Template) {
- subjectTemplates = subjectTpl
- bodyTemplates = bodyTpl
-}
-
// SendTestMail sends a test mail
func SendTestMail(email string) error {
if setting.MailService == nil {
diff --git a/services/mailer/mail_test.go b/services/mailer/mail_test.go
index 93837ba8c4ca..604efe37b642 100644
--- a/services/mailer/mail_test.go
+++ b/services/mailer/mail_test.go
@@ -67,9 +67,8 @@ func prepareMailerTest(t *testing.T) (doer *user_model.User, repo *repo_model.Re
func TestComposeIssueCommentMessage(t *testing.T) {
doer, _, issue, comment := prepareMailerTest(t)
- stpl := texttmpl.Must(texttmpl.New("issue/comment").Parse(subjectTpl))
- btpl := template.Must(template.New("issue/comment").Parse(bodyTpl))
- InitMailRender(stpl, btpl)
+ subjectTemplates = texttmpl.Must(texttmpl.New("issue/comment").Parse(subjectTpl))
+ bodyTemplates = template.Must(template.New("issue/comment").Parse(bodyTpl))
recipients := []*user_model.User{{Name: "Test", Email: "test@gitea.com"}, {Name: "Test2", Email: "test2@gitea.com"}}
msgs, err := composeIssueCommentMessages(&mailCommentContext{
@@ -97,9 +96,8 @@ func TestComposeIssueCommentMessage(t *testing.T) {
func TestComposeIssueMessage(t *testing.T) {
doer, _, issue, _ := prepareMailerTest(t)
- stpl := texttmpl.Must(texttmpl.New("issue/new").Parse(subjectTpl))
- btpl := template.Must(template.New("issue/new").Parse(bodyTpl))
- InitMailRender(stpl, btpl)
+ subjectTemplates = texttmpl.Must(texttmpl.New("issue/new").Parse(subjectTpl))
+ bodyTemplates = template.Must(template.New("issue/new").Parse(bodyTpl))
recipients := []*user_model.User{{Name: "Test", Email: "test@gitea.com"}, {Name: "Test2", Email: "test2@gitea.com"}}
msgs, err := composeIssueCommentMessages(&mailCommentContext{
@@ -128,17 +126,15 @@ func TestTemplateSelection(t *testing.T) {
doer, repo, issue, comment := prepareMailerTest(t)
recipients := []*user_model.User{{Name: "Test", Email: "test@gitea.com"}}
- stpl := texttmpl.Must(texttmpl.New("issue/default").Parse("issue/default/subject"))
- texttmpl.Must(stpl.New("issue/new").Parse("issue/new/subject"))
- texttmpl.Must(stpl.New("pull/comment").Parse("pull/comment/subject"))
- texttmpl.Must(stpl.New("issue/close").Parse("")) // Must default to fallback subject
+ subjectTemplates = texttmpl.Must(texttmpl.New("issue/default").Parse("issue/default/subject"))
+ texttmpl.Must(subjectTemplates.New("issue/new").Parse("issue/new/subject"))
+ texttmpl.Must(subjectTemplates.New("pull/comment").Parse("pull/comment/subject"))
+ texttmpl.Must(subjectTemplates.New("issue/close").Parse("")) // Must default to fallback subject
- btpl := template.Must(template.New("issue/default").Parse("issue/default/body"))
- template.Must(btpl.New("issue/new").Parse("issue/new/body"))
- template.Must(btpl.New("pull/comment").Parse("pull/comment/body"))
- template.Must(btpl.New("issue/close").Parse("issue/close/body"))
-
- InitMailRender(stpl, btpl)
+ bodyTemplates = template.Must(template.New("issue/default").Parse("issue/default/body"))
+ template.Must(bodyTemplates.New("issue/new").Parse("issue/new/body"))
+ template.Must(bodyTemplates.New("pull/comment").Parse("pull/comment/body"))
+ template.Must(bodyTemplates.New("issue/close").Parse("issue/close/body"))
expect := func(t *testing.T, msg *Message, expSubject, expBody string) {
subject := msg.ToMessage().GetHeader("Subject")
@@ -187,9 +183,8 @@ func TestTemplateServices(t *testing.T) {
expect := func(t *testing.T, issue *issues_model.Issue, comment *issues_model.Comment, doer *user_model.User,
actionType models.ActionType, fromMention bool, tplSubject, tplBody, expSubject, expBody string,
) {
- stpl := texttmpl.Must(texttmpl.New("issue/default").Parse(tplSubject))
- btpl := template.Must(template.New("issue/default").Parse(tplBody))
- InitMailRender(stpl, btpl)
+ subjectTemplates = texttmpl.Must(texttmpl.New("issue/default").Parse(tplSubject))
+ bodyTemplates = template.Must(template.New("issue/default").Parse(tplBody))
recipients := []*user_model.User{{Name: "Test", Email: "test@gitea.com"}}
msg := testComposeIssueCommentMessage(t, &mailCommentContext{
diff --git a/services/mailer/mailer.go b/services/mailer/mailer.go
index c86c54c748c5..fdbb6e562bfc 100644
--- a/services/mailer/mailer.go
+++ b/services/mailer/mailer.go
@@ -24,6 +24,7 @@ import (
"code.gitea.io/gitea/modules/process"
"code.gitea.io/gitea/modules/queue"
"code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/templates"
"github.com/jaytaylor/html2text"
"gopkg.in/gomail.v2"
@@ -379,6 +380,8 @@ func NewContext() {
}, &Message{})
go graceful.GetManager().RunWithShutdownFns(mailQueue.Run)
+
+ subjectTemplates, bodyTemplates = templates.Mailer()
}
// SendAsync send mail asynchronously
diff --git a/templates/repo/branch/list.tmpl b/templates/repo/branch/list.tmpl
index 4a85692a8315..09799fbece57 100644
--- a/templates/repo/branch/list.tmpl
+++ b/templates/repo/branch/list.tmpl
@@ -112,7 +112,7 @@
{{svg "octicon-git-branch"}}
{{end}}
- {{if (not .IsDeleted)}}
+ {{if and (not .IsDeleted) (not $.DisableDownloadSourceArchives)}}