aboutsummaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
Diffstat (limited to 'services')
-rw-r--r--services/auth/source/oauth2/urlmapping.go10
-rw-r--r--services/context/api.go9
-rw-r--r--services/context/permission.go7
-rw-r--r--services/context/upload/upload.go2
-rw-r--r--services/doctor/repository.go4
-rw-r--r--services/feed/feed_test.go2
-rw-r--r--services/gitdiff/csv.go10
-rw-r--r--services/gitdiff/gitdiff.go5
-rw-r--r--services/gitdiff/gitdiff_test.go6
-rw-r--r--services/gitdiff/submodule_test.go1
-rw-r--r--services/lfs/locks.go10
-rw-r--r--services/lfs/server.go5
-rw-r--r--services/mailer/sender/message_test.go4
-rw-r--r--services/migrations/codecommit.go5
-rw-r--r--services/migrations/github.go4
-rw-r--r--services/oauth2_provider/access_token.go2
-rw-r--r--services/org/team_test.go6
-rw-r--r--services/packages/arch/vercmp.go7
-rw-r--r--services/packages/cargo/index.go2
-rw-r--r--services/packages/cleanup/cleanup.go211
-rw-r--r--services/packages/container/cleanup.go2
-rw-r--r--services/pull/merge.go5
-rw-r--r--services/repository/adopt.go9
-rw-r--r--services/repository/adopt_test.go2
-rw-r--r--services/repository/check.go2
-rw-r--r--services/repository/commitstatus/commitstatus.go2
-rw-r--r--services/repository/create.go16
-rw-r--r--services/repository/create_test.go2
-rw-r--r--services/repository/delete.go4
-rw-r--r--services/repository/files/diff.go2
-rw-r--r--services/repository/files/file.go2
-rw-r--r--services/repository/files/temp_repo.go6
-rw-r--r--services/repository/files/tree.go6
-rw-r--r--services/repository/files/update.go308
-rw-r--r--services/repository/files/upload.go4
-rw-r--r--services/repository/fork.go14
-rw-r--r--services/repository/fork_test.go2
-rw-r--r--services/repository/generate.go28
-rw-r--r--services/repository/gitgraph/graph_models.go4
-rw-r--r--services/repository/gitgraph/graph_test.go25
-rw-r--r--services/repository/migrate.go6
-rw-r--r--services/repository/push.go32
-rw-r--r--services/repository/repository.go85
-rw-r--r--services/repository/template.go2
-rw-r--r--services/webtheme/webtheme.go8
-rw-r--r--services/wiki/wiki_test.go4
46 files changed, 448 insertions, 446 deletions
diff --git a/services/auth/source/oauth2/urlmapping.go b/services/auth/source/oauth2/urlmapping.go
index d0442d58a8..b9f445caa7 100644
--- a/services/auth/source/oauth2/urlmapping.go
+++ b/services/auth/source/oauth2/urlmapping.go
@@ -14,11 +14,11 @@ type CustomURLMapping struct {
// CustomURLSettings describes the urls values and availability to use when customizing OAuth2 provider URLs
type CustomURLSettings struct {
- AuthURL Attribute `json:",omitempty"`
- TokenURL Attribute `json:",omitempty"`
- ProfileURL Attribute `json:",omitempty"`
- EmailURL Attribute `json:",omitempty"`
- Tenant Attribute `json:",omitempty"`
+ AuthURL Attribute
+ TokenURL Attribute
+ ProfileURL Attribute
+ EmailURL Attribute
+ Tenant Attribute
}
// Attribute describes the availability, and required status for a custom url configuration
diff --git a/services/context/api.go b/services/context/api.go
index 28f0e43d88..ab50a360f4 100644
--- a/services/context/api.go
+++ b/services/context/api.go
@@ -9,6 +9,7 @@ import (
"fmt"
"net/http"
"net/url"
+ "slices"
"strconv"
"strings"
@@ -364,11 +365,5 @@ func (ctx *APIContext) IsUserRepoAdmin() bool {
// IsUserRepoWriter returns true if current user has "write" privilege in current repo
func (ctx *APIContext) IsUserRepoWriter(unitTypes []unit.Type) bool {
- for _, unitType := range unitTypes {
- if ctx.Repo.CanWrite(unitType) {
- return true
- }
- }
-
- return false
+ return slices.ContainsFunc(unitTypes, ctx.Repo.CanWrite)
}
diff --git a/services/context/permission.go b/services/context/permission.go
index 7055f798da..c0a5a98724 100644
--- a/services/context/permission.go
+++ b/services/context/permission.go
@@ -5,6 +5,7 @@ package context
import (
"net/http"
+ "slices"
auth_model "code.gitea.io/gitea/models/auth"
repo_model "code.gitea.io/gitea/models/repo"
@@ -34,10 +35,8 @@ func CanWriteToBranch() func(ctx *Context) {
// RequireUnitWriter returns a middleware for requiring repository write to one of the unit permission
func RequireUnitWriter(unitTypes ...unit.Type) func(ctx *Context) {
return func(ctx *Context) {
- for _, unitType := range unitTypes {
- if ctx.Repo.CanWrite(unitType) {
- return
- }
+ if slices.ContainsFunc(unitTypes, ctx.Repo.CanWrite) {
+ return
}
ctx.NotFound(nil)
}
diff --git a/services/context/upload/upload.go b/services/context/upload/upload.go
index 12aa485aa7..5edddc6f27 100644
--- a/services/context/upload/upload.go
+++ b/services/context/upload/upload.go
@@ -39,7 +39,7 @@ func Verify(buf []byte, fileName, allowedTypesStr string) error {
allowedTypesStr = strings.ReplaceAll(allowedTypesStr, "|", ",") // compat for old config format
allowedTypes := []string{}
- for _, entry := range strings.Split(allowedTypesStr, ",") {
+ for entry := range strings.SplitSeq(allowedTypesStr, ",") {
entry = strings.ToLower(strings.TrimSpace(entry))
if entry != "" {
allowedTypes = append(allowedTypes, entry)
diff --git a/services/doctor/repository.go b/services/doctor/repository.go
index 6c33426636..359c4a17e0 100644
--- a/services/doctor/repository.go
+++ b/services/doctor/repository.go
@@ -7,7 +7,6 @@ import (
"context"
"code.gitea.io/gitea/models/db"
- user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/storage"
repo_service "code.gitea.io/gitea/services/repository"
@@ -39,7 +38,6 @@ func deleteOrphanedRepos(ctx context.Context) (int64, error) {
batchSize := db.MaxBatchInsertSize("repository")
e := db.GetEngine(ctx)
var deleted int64
- adminUser := &user_model.User{IsAdmin: true}
for {
select {
@@ -60,7 +58,7 @@ func deleteOrphanedRepos(ctx context.Context) (int64, error) {
}
for _, id := range ids {
- if err := repo_service.DeleteRepositoryDirectly(ctx, adminUser, id, true); err != nil {
+ if err := repo_service.DeleteRepositoryDirectly(ctx, id, true); err != nil {
return deleted, err
}
deleted++
diff --git a/services/feed/feed_test.go b/services/feed/feed_test.go
index a3492938c8..705d42a2eb 100644
--- a/services/feed/feed_test.go
+++ b/services/feed/feed_test.go
@@ -147,7 +147,7 @@ func TestRepoActions(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
_ = db.TruncateBeans(db.DefaultContext, &activities_model.Action{})
- for i := 0; i < 3; i++ {
+ for i := range 3 {
_ = db.Insert(db.DefaultContext, &activities_model.Action{
UserID: 2 + int64(i),
ActUserID: 2,
diff --git a/services/gitdiff/csv.go b/services/gitdiff/csv.go
index 8db73c56a3..c10ee14490 100644
--- a/services/gitdiff/csv.go
+++ b/services/gitdiff/csv.go
@@ -134,7 +134,7 @@ func createCsvDiffSingle(reader *csv.Reader, celltype TableDiffCellType) ([]*Tab
return nil, err
}
cells := make([]*TableDiffCell, len(row))
- for j := 0; j < len(row); j++ {
+ for j := range row {
if celltype == TableDiffCellDel {
cells[j] = &TableDiffCell{LeftCell: row[j], Type: celltype}
} else {
@@ -365,11 +365,11 @@ func getColumnMapping(baseCSVReader, headCSVReader *csvReader) ([]int, []int) {
}
// Loops through the baseRow and see if there is a match in the head row
- for i := 0; i < len(baseRow); i++ {
+ for i := range baseRow {
base2HeadColMap[i] = unmappedColumn
baseCell, err := getCell(baseRow, i)
if err == nil {
- for j := 0; j < len(headRow); j++ {
+ for j := range headRow {
if head2BaseColMap[j] == -1 {
headCell, err := getCell(headRow, j)
if err == nil && baseCell == headCell {
@@ -390,7 +390,7 @@ func getColumnMapping(baseCSVReader, headCSVReader *csvReader) ([]int, []int) {
// tryMapColumnsByContent tries to map missing columns by the content of the first lines.
func tryMapColumnsByContent(baseCSVReader *csvReader, base2HeadColMap []int, headCSVReader *csvReader, head2BaseColMap []int) {
- for i := 0; i < len(base2HeadColMap); i++ {
+ for i := range base2HeadColMap {
headStart := 0
for base2HeadColMap[i] == unmappedColumn && headStart < len(head2BaseColMap) {
if head2BaseColMap[headStart] == unmappedColumn {
@@ -424,7 +424,7 @@ func getCell(row []string, column int) (string, error) {
// countUnmappedColumns returns the count of unmapped columns.
func countUnmappedColumns(mapping []int) int {
count := 0
- for i := 0; i < len(mapping); i++ {
+ for i := range mapping {
if mapping[i] == unmappedColumn {
count++
}
diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go
index a859945378..895cbe5a2f 100644
--- a/services/gitdiff/gitdiff.go
+++ b/services/gitdiff/gitdiff.go
@@ -540,10 +540,7 @@ func ParsePatch(ctx context.Context, maxLines, maxLineCharacters, maxFiles int,
// OK let's set a reasonable buffer size.
// This should be at least the size of maxLineCharacters or 4096 whichever is larger.
- readerSize := maxLineCharacters
- if readerSize < 4096 {
- readerSize = 4096
- }
+ readerSize := max(maxLineCharacters, 4096)
input := bufio.NewReaderSize(reader, readerSize)
line, err := input.ReadString('\n')
diff --git a/services/gitdiff/gitdiff_test.go b/services/gitdiff/gitdiff_test.go
index 71394b1915..b84530043a 100644
--- a/services/gitdiff/gitdiff_test.go
+++ b/services/gitdiff/gitdiff_test.go
@@ -416,7 +416,7 @@ index 0000000..6bb8f39
`
diffBuilder.WriteString(diff)
- for i := 0; i < 35; i++ {
+ for i := range 35 {
diffBuilder.WriteString("+line" + strconv.Itoa(i) + "\n")
}
diff = diffBuilder.String()
@@ -453,11 +453,11 @@ index 0000000..6bb8f39
diffBuilder.Reset()
diffBuilder.WriteString(diff)
- for i := 0; i < 33; i++ {
+ for i := range 33 {
diffBuilder.WriteString("+line" + strconv.Itoa(i) + "\n")
}
diffBuilder.WriteString("+line33")
- for i := 0; i < 512; i++ {
+ for range 512 {
diffBuilder.WriteString("0123456789ABCDEF")
}
diffBuilder.WriteByte('\n')
diff --git a/services/gitdiff/submodule_test.go b/services/gitdiff/submodule_test.go
index 3047b23103..152c5b7066 100644
--- a/services/gitdiff/submodule_test.go
+++ b/services/gitdiff/submodule_test.go
@@ -203,7 +203,6 @@ index 0000000..68972a9
}
for _, testcase := range tests {
- testcase := testcase
t.Run(testcase.name, func(t *testing.T) {
diff, err := ParsePatch(db.DefaultContext, setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(testcase.gitdiff), "")
assert.NoError(t, err)
diff --git a/services/lfs/locks.go b/services/lfs/locks.go
index 1d464f4a66..264001f0f9 100644
--- a/services/lfs/locks.go
+++ b/services/lfs/locks.go
@@ -74,10 +74,7 @@ func GetListLockHandler(ctx *context.Context) {
}
ctx.Resp.Header().Set("Content-Type", lfs_module.MediaType)
- cursor := ctx.FormInt("cursor")
- if cursor < 0 {
- cursor = 0
- }
+ cursor := max(ctx.FormInt("cursor"), 0)
limit := ctx.FormInt("limit")
if limit > setting.LFS.LocksPagingNum && setting.LFS.LocksPagingNum > 0 {
limit = setting.LFS.LocksPagingNum
@@ -239,10 +236,7 @@ func VerifyLockHandler(ctx *context.Context) {
ctx.Resp.Header().Set("Content-Type", lfs_module.MediaType)
- cursor := ctx.FormInt("cursor")
- if cursor < 0 {
- cursor = 0
- }
+ cursor := max(ctx.FormInt("cursor"), 0)
limit := ctx.FormInt("limit")
if limit > setting.LFS.LocksPagingNum && setting.LFS.LocksPagingNum > 0 {
limit = setting.LFS.LocksPagingNum
diff --git a/services/lfs/server.go b/services/lfs/server.go
index 0a99287ed9..59c9884fa8 100644
--- a/services/lfs/server.go
+++ b/services/lfs/server.go
@@ -11,6 +11,7 @@ import (
"errors"
"fmt"
"io"
+ "maps"
"net/http"
"net/url"
"path"
@@ -480,9 +481,7 @@ func buildObjectResponse(rc *requestContext, pointer lfs_module.Pointer, downloa
rep.Actions["upload"] = &lfs_module.Link{Href: rc.UploadLink(pointer), Header: header}
verifyHeader := make(map[string]string)
- for key, value := range header {
- verifyHeader[key] = value
- }
+ maps.Copy(verifyHeader, header)
// This is only needed to workaround https://github.com/git-lfs/git-lfs/issues/3662
verifyHeader["Accept"] = lfs_module.AcceptHeader
diff --git a/services/mailer/sender/message_test.go b/services/mailer/sender/message_test.go
index 63d0bc349a..ae153ebf05 100644
--- a/services/mailer/sender/message_test.go
+++ b/services/mailer/sender/message_test.go
@@ -108,9 +108,9 @@ func extractMailHeaderAndContent(t *testing.T, mail string) (map[string]string,
}
content := strings.TrimSpace("boundary=" + parts[1])
- hParts := strings.Split(parts[0], "\n")
+ hParts := strings.SplitSeq(parts[0], "\n")
- for _, hPart := range hParts {
+ for hPart := range hParts {
parts := strings.SplitN(hPart, ":", 2)
hk := strings.TrimSpace(parts[0])
if hk != "" {
diff --git a/services/migrations/codecommit.go b/services/migrations/codecommit.go
index 9317156ab0..d08b2e6d4a 100644
--- a/services/migrations/codecommit.go
+++ b/services/migrations/codecommit.go
@@ -155,10 +155,7 @@ func (c *CodeCommitDownloader) GetPullRequests(ctx context.Context, page, perPag
}
startIndex := (page - 1) * perPage
- endIndex := page * perPage
- if endIndex > len(allPullRequestIDs) {
- endIndex = len(allPullRequestIDs)
- }
+ endIndex := min(page*perPage, len(allPullRequestIDs))
batch := allPullRequestIDs[startIndex:endIndex]
prs := make([]*base.PullRequest, 0, len(batch))
diff --git a/services/migrations/github.go b/services/migrations/github.go
index 662908756a..2ce11615c6 100644
--- a/services/migrations/github.go
+++ b/services/migrations/github.go
@@ -89,8 +89,8 @@ func NewGithubDownloaderV3(_ context.Context, baseURL, userName, password, token
}
if token != "" {
- tokens := strings.Split(token, ",")
- for _, token := range tokens {
+ tokens := strings.SplitSeq(token, ",")
+ for token := range tokens {
token = strings.TrimSpace(token)
ts := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: token},
diff --git a/services/oauth2_provider/access_token.go b/services/oauth2_provider/access_token.go
index 4173b0fe87..b9e6d7517b 100644
--- a/services/oauth2_provider/access_token.go
+++ b/services/oauth2_provider/access_token.go
@@ -85,7 +85,7 @@ func GrantAdditionalScopes(grantScopes string) auth.AccessTokenScope {
}
var accessScopes []string // the scopes for access control, but not for general information
- for _, scope := range strings.Split(grantScopes, " ") {
+ for scope := range strings.SplitSeq(grantScopes, " ") {
if scope != "" && !slices.Contains(generalScopesSupported, scope) {
accessScopes = append(accessScopes, scope)
}
diff --git a/services/org/team_test.go b/services/org/team_test.go
index aa39771cd2..c1a69d8ee7 100644
--- a/services/org/team_test.go
+++ b/services/org/team_test.go
@@ -204,7 +204,7 @@ func TestIncludesAllRepositoriesTeams(t *testing.T) {
// Create repos.
repoIDs := make([]int64, 0)
- for i := 0; i < 3; i++ {
+ for i := range 3 {
r, err := repo_service.CreateRepositoryDirectly(db.DefaultContext, user, org.AsUser(),
repo_service.CreateRepoOptions{Name: fmt.Sprintf("repo-%d", i)}, true)
assert.NoError(t, err, "CreateRepository %d", i)
@@ -281,7 +281,7 @@ func TestIncludesAllRepositoriesTeams(t *testing.T) {
}
// Remove repo and check teams repositories.
- assert.NoError(t, repo_service.DeleteRepositoryDirectly(db.DefaultContext, user, repoIDs[0]), "DeleteRepository")
+ assert.NoError(t, repo_service.DeleteRepositoryDirectly(db.DefaultContext, repoIDs[0]), "DeleteRepository")
teamRepos[0] = repoIDs[1:]
teamRepos[1] = repoIDs[1:]
teamRepos[3] = repoIDs[1:3]
@@ -293,7 +293,7 @@ func TestIncludesAllRepositoriesTeams(t *testing.T) {
// Wipe created items.
for i, rid := range repoIDs {
if i > 0 { // first repo already deleted.
- assert.NoError(t, repo_service.DeleteRepositoryDirectly(db.DefaultContext, user, rid), "DeleteRepository %d", i)
+ assert.NoError(t, repo_service.DeleteRepositoryDirectly(db.DefaultContext, rid), "DeleteRepository %d", i)
}
}
assert.NoError(t, DeleteOrganization(db.DefaultContext, org, false), "DeleteOrganization")
diff --git a/services/packages/arch/vercmp.go b/services/packages/arch/vercmp.go
index 0d33dda0f1..6dcd0df419 100644
--- a/services/packages/arch/vercmp.go
+++ b/services/packages/arch/vercmp.go
@@ -34,12 +34,7 @@ func parseEVR(evr string) (epoch, version, release string) {
func compareSegments(a, b []string) int {
lenA, lenB := len(a), len(b)
- var l int
- if lenA > lenB {
- l = lenB
- } else {
- l = lenA
- }
+ l := min(lenA, lenB)
for i := 0; i < l; i++ {
if r := compare(a[i], b[i]); r != 0 {
return r
diff --git a/services/packages/cargo/index.go b/services/packages/cargo/index.go
index e8a2f189c8..605335d0f1 100644
--- a/services/packages/cargo/index.go
+++ b/services/packages/cargo/index.go
@@ -310,7 +310,7 @@ func alterRepositoryContent(ctx context.Context, doer *user_model.User, repo *re
}
func writeObjectToIndex(ctx context.Context, t *files_service.TemporaryUploadRepository, path string, r io.Reader) error {
- hash, err := t.HashObject(ctx, r)
+ hash, err := t.HashObjectAndWrite(ctx, r)
if err != nil {
return err
}
diff --git a/services/packages/cleanup/cleanup.go b/services/packages/cleanup/cleanup.go
index b7ba2b6ac4..959babe7cd 100644
--- a/services/packages/cleanup/cleanup.go
+++ b/services/packages/cleanup/cleanup.go
@@ -32,127 +32,136 @@ func CleanupTask(ctx context.Context, olderThan time.Duration) error {
return CleanupExpiredData(ctx, olderThan)
}
-func ExecuteCleanupRules(outerCtx context.Context) error {
- ctx, committer, err := db.TxContext(outerCtx)
+func executeCleanupOneRulePackage(ctx context.Context, pcr *packages_model.PackageCleanupRule, p *packages_model.Package) (versionDeleted bool, err error) {
+ olderThan := time.Now().AddDate(0, 0, -pcr.RemoveDays)
+ pvs, _, err := packages_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{
+ PackageID: p.ID,
+ IsInternal: optional.Some(false),
+ Sort: packages_model.SortCreatedDesc,
+ })
if err != nil {
- return err
+ return false, fmt.Errorf("CleanupRule [%d]: SearchVersions failed: %w", pcr.ID, err)
}
- defer committer.Close()
-
- err = packages_model.IterateEnabledCleanupRules(ctx, func(ctx context.Context, pcr *packages_model.PackageCleanupRule) error {
- select {
- case <-outerCtx.Done():
- return db.ErrCancelledf("While processing package cleanup rules")
- default:
+ if pcr.KeepCount > 0 {
+ if pcr.KeepCount < len(pvs) {
+ pvs = pvs[pcr.KeepCount:]
+ } else {
+ pvs = nil
}
-
- if err := pcr.CompiledPattern(); err != nil {
- return fmt.Errorf("CleanupRule [%d]: CompilePattern failed: %w", pcr.ID, err)
+ }
+ for _, pv := range pvs {
+ if pcr.Type == packages_model.TypeContainer {
+ if skip, err := container_service.ShouldBeSkipped(ctx, pcr, p, pv); err != nil {
+ return false, fmt.Errorf("CleanupRule [%d]: container.ShouldBeSkipped failed: %w", pcr.ID, err)
+ } else if skip {
+ log.Debug("Rule[%d]: keep '%s/%s' (container)", pcr.ID, p.Name, pv.Version)
+ continue
+ }
}
-
- olderThan := time.Now().AddDate(0, 0, -pcr.RemoveDays)
-
- packages, err := packages_model.GetPackagesByType(ctx, pcr.OwnerID, pcr.Type)
- if err != nil {
- return fmt.Errorf("CleanupRule [%d]: GetPackagesByType failed: %w", pcr.ID, err)
+ toMatch := pv.LowerVersion
+ if pcr.MatchFullName {
+ toMatch = p.LowerName + "/" + pv.LowerVersion
+ }
+ if pcr.KeepPatternMatcher != nil && pcr.KeepPatternMatcher.MatchString(toMatch) {
+ log.Debug("Rule[%d]: keep '%s/%s' (keep pattern)", pcr.ID, p.Name, pv.Version)
+ continue
+ }
+ if pv.CreatedUnix.AsLocalTime().After(olderThan) {
+ log.Debug("Rule[%d]: keep '%s/%s' (remove days) %v", pcr.ID, p.Name, pv.Version, pv.CreatedUnix.FormatDate())
+ continue
}
+ if pcr.RemovePatternMatcher != nil && !pcr.RemovePatternMatcher.MatchString(toMatch) {
+ log.Debug("Rule[%d]: keep '%s/%s' (remove pattern)", pcr.ID, p.Name, pv.Version)
+ continue
+ }
+ log.Debug("Rule[%d]: remove '%s/%s'", pcr.ID, p.Name, pv.Version)
+ if err := packages_service.DeletePackageVersionAndReferences(ctx, pv); err != nil {
+ log.Error("CleanupRule [%d]: DeletePackageVersionAndReferences failed: %v", pcr.ID, err)
+ continue
+ }
+ versionDeleted = true
+ }
+ return versionDeleted, nil
+}
- anyVersionDeleted := false
- for _, p := range packages {
- pvs, _, err := packages_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{
- PackageID: p.ID,
- IsInternal: optional.Some(false),
- Sort: packages_model.SortCreatedDesc,
- Paginator: db.NewAbsoluteListOptions(pcr.KeepCount, 200),
- })
- if err != nil {
- return fmt.Errorf("CleanupRule [%d]: SearchVersions failed: %w", pcr.ID, err)
- }
- versionDeleted := false
- for _, pv := range pvs {
- if pcr.Type == packages_model.TypeContainer {
- if skip, err := container_service.ShouldBeSkipped(ctx, pcr, p, pv); err != nil {
- return fmt.Errorf("CleanupRule [%d]: container.ShouldBeSkipped failed: %w", pcr.ID, err)
- } else if skip {
- log.Debug("Rule[%d]: keep '%s/%s' (container)", pcr.ID, p.Name, pv.Version)
- continue
- }
- }
+func executeCleanupOneRule(ctx context.Context, pcr *packages_model.PackageCleanupRule) error {
+ if err := pcr.CompiledPattern(); err != nil {
+ return fmt.Errorf("CleanupRule [%d]: CompilePattern failed: %w", pcr.ID, err)
+ }
- toMatch := pv.LowerVersion
- if pcr.MatchFullName {
- toMatch = p.LowerName + "/" + pv.LowerVersion
- }
+ packages, err := packages_model.GetPackagesByType(ctx, pcr.OwnerID, pcr.Type)
+ if err != nil {
+ return fmt.Errorf("CleanupRule [%d]: GetPackagesByType failed: %w", pcr.ID, err)
+ }
- if pcr.KeepPatternMatcher != nil && pcr.KeepPatternMatcher.MatchString(toMatch) {
- log.Debug("Rule[%d]: keep '%s/%s' (keep pattern)", pcr.ID, p.Name, pv.Version)
- continue
- }
- if pv.CreatedUnix.AsLocalTime().After(olderThan) {
- log.Debug("Rule[%d]: keep '%s/%s' (remove days)", pcr.ID, p.Name, pv.Version)
- continue
- }
- if pcr.RemovePatternMatcher != nil && !pcr.RemovePatternMatcher.MatchString(toMatch) {
- log.Debug("Rule[%d]: keep '%s/%s' (remove pattern)", pcr.ID, p.Name, pv.Version)
- continue
+ anyVersionDeleted := false
+ for _, p := range packages {
+ versionDeleted := false
+ err = db.WithTx(ctx, func(ctx context.Context) (err error) {
+ versionDeleted, err = executeCleanupOneRulePackage(ctx, pcr, p)
+ return err
+ })
+ if err != nil {
+ log.Error("CleanupRule [%d]: executeCleanupOneRulePackage(%d) failed: %v", pcr.ID, p.ID, err)
+ continue
+ }
+ anyVersionDeleted = anyVersionDeleted || versionDeleted
+ if versionDeleted {
+ if pcr.Type == packages_model.TypeCargo {
+ owner, err := user_model.GetUserByID(ctx, pcr.OwnerID)
+ if err != nil {
+ return fmt.Errorf("GetUserByID failed: %w", err)
}
-
- log.Debug("Rule[%d]: remove '%s/%s'", pcr.ID, p.Name, pv.Version)
-
- if err := packages_service.DeletePackageVersionAndReferences(ctx, pv); err != nil {
- return fmt.Errorf("CleanupRule [%d]: DeletePackageVersionAndReferences failed: %w", pcr.ID, err)
+ if err := cargo_service.UpdatePackageIndexIfExists(ctx, owner, owner, p.ID); err != nil {
+ return fmt.Errorf("CleanupRule [%d]: cargo.UpdatePackageIndexIfExists failed: %w", pcr.ID, err)
}
+ }
+ }
+ }
- versionDeleted = true
- anyVersionDeleted = true
+ if anyVersionDeleted {
+ switch pcr.Type {
+ case packages_model.TypeDebian:
+ if err := debian_service.BuildAllRepositoryFiles(ctx, pcr.OwnerID); err != nil {
+ return fmt.Errorf("CleanupRule [%d]: debian.BuildAllRepositoryFiles failed: %w", pcr.ID, err)
+ }
+ case packages_model.TypeAlpine:
+ if err := alpine_service.BuildAllRepositoryFiles(ctx, pcr.OwnerID); err != nil {
+ return fmt.Errorf("CleanupRule [%d]: alpine.BuildAllRepositoryFiles failed: %w", pcr.ID, err)
}
+ case packages_model.TypeRpm:
+ if err := rpm_service.BuildAllRepositoryFiles(ctx, pcr.OwnerID); err != nil {
+ return fmt.Errorf("CleanupRule [%d]: rpm.BuildAllRepositoryFiles failed: %w", pcr.ID, err)
+ }
+ case packages_model.TypeArch:
+ release, err := arch_service.AquireRegistryLock(ctx, pcr.OwnerID)
+ if err != nil {
+ return err
+ }
+ defer release()
- if versionDeleted {
- if pcr.Type == packages_model.TypeCargo {
- owner, err := user_model.GetUserByID(ctx, pcr.OwnerID)
- if err != nil {
- return fmt.Errorf("GetUserByID failed: %w", err)
- }
- if err := cargo_service.UpdatePackageIndexIfExists(ctx, owner, owner, p.ID); err != nil {
- return fmt.Errorf("CleanupRule [%d]: cargo.UpdatePackageIndexIfExists failed: %w", pcr.ID, err)
- }
- }
+ if err := arch_service.BuildAllRepositoryFiles(ctx, pcr.OwnerID); err != nil {
+ return fmt.Errorf("CleanupRule [%d]: arch.BuildAllRepositoryFiles failed: %w", pcr.ID, err)
}
}
+ }
+ return nil
+}
- if anyVersionDeleted {
- switch pcr.Type {
- case packages_model.TypeDebian:
- if err := debian_service.BuildAllRepositoryFiles(ctx, pcr.OwnerID); err != nil {
- return fmt.Errorf("CleanupRule [%d]: debian.BuildAllRepositoryFiles failed: %w", pcr.ID, err)
- }
- case packages_model.TypeAlpine:
- if err := alpine_service.BuildAllRepositoryFiles(ctx, pcr.OwnerID); err != nil {
- return fmt.Errorf("CleanupRule [%d]: alpine.BuildAllRepositoryFiles failed: %w", pcr.ID, err)
- }
- case packages_model.TypeRpm:
- if err := rpm_service.BuildAllRepositoryFiles(ctx, pcr.OwnerID); err != nil {
- return fmt.Errorf("CleanupRule [%d]: rpm.BuildAllRepositoryFiles failed: %w", pcr.ID, err)
- }
- case packages_model.TypeArch:
- release, err := arch_service.AquireRegistryLock(ctx, pcr.OwnerID)
- if err != nil {
- return err
- }
- defer release()
+func ExecuteCleanupRules(ctx context.Context) error {
+ return packages_model.IterateEnabledCleanupRules(ctx, func(ctx context.Context, pcr *packages_model.PackageCleanupRule) error {
+ select {
+ case <-ctx.Done():
+ return db.ErrCancelledf("While processing package cleanup rules")
+ default:
+ }
- if err := arch_service.BuildAllRepositoryFiles(ctx, pcr.OwnerID); err != nil {
- return fmt.Errorf("CleanupRule [%d]: arch.BuildAllRepositoryFiles failed: %w", pcr.ID, err)
- }
- }
+ err := executeCleanupOneRule(ctx, pcr)
+ if err != nil {
+ log.Error("CleanupRule [%d]: executeCleanupOneRule failed: %v", pcr.ID, err)
}
return nil
})
- if err != nil {
- return err
- }
-
- return committer.Commit()
}
func CleanupExpiredData(outerCtx context.Context, olderThan time.Duration) error {
diff --git a/services/packages/container/cleanup.go b/services/packages/container/cleanup.go
index 3f5f43bbc0..d15d6b6c84 100644
--- a/services/packages/container/cleanup.go
+++ b/services/packages/container/cleanup.go
@@ -57,7 +57,7 @@ func cleanupExpiredUploadedBlobs(ctx context.Context, olderThan time.Duration) e
Type: packages_model.TypeContainer,
Version: packages_model.SearchValue{
ExactMatch: true,
- Value: container_model.UploadVersion,
+ Value: container_module.UploadVersion,
},
IsInternal: optional.Some(true),
HasFiles: optional.Some(false),
diff --git a/services/pull/merge.go b/services/pull/merge.go
index 2a2f47e880..7a74bf55ae 100644
--- a/services/pull/merge.go
+++ b/services/pull/merge.go
@@ -8,6 +8,7 @@ import (
"context"
"errors"
"fmt"
+ "maps"
"os"
"path/filepath"
"regexp"
@@ -95,9 +96,7 @@ func getMergeMessage(ctx context.Context, baseGitRepo *git.Repository, pr *issue
vars["HeadRepoOwnerName"] = pr.HeadRepo.OwnerName
vars["HeadRepoName"] = pr.HeadRepo.Name
}
- for extraKey, extraValue := range extraVars {
- vars[extraKey] = extraValue
- }
+ maps.Copy(vars, extraVars)
refs, err := pr.ResolveCrossReferences(ctx)
if err == nil {
closeIssueIndexes := make([]string, 0, len(refs))
diff --git a/services/repository/adopt.go b/services/repository/adopt.go
index 3b958e0d4c..2bd1c55de4 100644
--- a/services/repository/adopt.go
+++ b/services/repository/adopt.go
@@ -196,8 +196,13 @@ func adoptRepository(ctx context.Context, repo *repo_model.Repository, defaultBr
return fmt.Errorf("setDefaultBranch: %w", err)
}
}
- if err = updateRepository(ctx, repo, false); err != nil {
- return fmt.Errorf("updateRepository: %w", err)
+
+ if err = repo_model.UpdateRepositoryColsNoAutoTime(ctx, repo, "is_empty", "default_branch"); err != nil {
+ return fmt.Errorf("UpdateRepositoryCols: %w", err)
+ }
+
+ if err = repo_module.UpdateRepoSize(ctx, repo); err != nil {
+ log.Error("Failed to update size for repository: %v", err)
}
return nil
diff --git a/services/repository/adopt_test.go b/services/repository/adopt_test.go
index 6e1dc417b3..86f586c748 100644
--- a/services/repository/adopt_test.go
+++ b/services/repository/adopt_test.go
@@ -29,7 +29,7 @@ func TestCheckUnadoptedRepositories_Add(t *testing.T) {
}
total := 30
- for i := 0; i < total; i++ {
+ for range total {
unadopted.add("something")
}
diff --git a/services/repository/check.go b/services/repository/check.go
index b475fbc487..ffcd5ac749 100644
--- a/services/repository/check.go
+++ b/services/repository/check.go
@@ -162,7 +162,7 @@ func DeleteMissingRepositories(ctx context.Context, doer *user_model.User) error
default:
}
log.Trace("Deleting %d/%d...", repo.OwnerID, repo.ID)
- if err := DeleteRepositoryDirectly(ctx, doer, repo.ID); err != nil {
+ if err := DeleteRepositoryDirectly(ctx, repo.ID); err != nil {
log.Error("Failed to DeleteRepository %-v: Error: %v", repo, err)
if err2 := system_model.CreateRepositoryNotice("Failed to DeleteRepository %s [%d]: Error: %v", repo.FullName(), repo.ID, err); err2 != nil {
log.Error("CreateRepositoryNotice: %v", err)
diff --git a/services/repository/commitstatus/commitstatus.go b/services/repository/commitstatus/commitstatus.go
index 44cf61df43..fa7a89882a 100644
--- a/services/repository/commitstatus/commitstatus.go
+++ b/services/repository/commitstatus/commitstatus.go
@@ -24,7 +24,7 @@ import (
)
func getCacheKey(repoID int64, brancheName string) string {
- hashBytes := sha256.Sum256([]byte(fmt.Sprintf("%d:%s", repoID, brancheName)))
+ hashBytes := sha256.Sum256(fmt.Appendf(nil, "%d:%s", repoID, brancheName))
return fmt.Sprintf("commit_status:%x", hashBytes)
}
diff --git a/services/repository/create.go b/services/repository/create.go
index 83d7d84c08..bed02e5d7e 100644
--- a/services/repository/create.go
+++ b/services/repository/create.go
@@ -100,8 +100,8 @@ func prepareRepoCommit(ctx context.Context, repo *repo_model.Repository, tmpDir
// .gitignore
if len(opts.Gitignores) > 0 {
var buf bytes.Buffer
- names := strings.Split(opts.Gitignores, ",")
- for _, name := range names {
+ names := strings.SplitSeq(opts.Gitignores, ",")
+ for name := range names {
data, err = options.Gitignore(name)
if err != nil {
return fmt.Errorf("GetRepoInitFile[%s]: %w", name, err)
@@ -191,10 +191,14 @@ func initRepository(ctx context.Context, u *user_model.User, repo *repo_model.Re
}
}
- if err = UpdateRepository(ctx, repo, false); err != nil {
+ if err = repo_model.UpdateRepositoryColsNoAutoTime(ctx, repo, "is_empty", "default_branch", "default_wiki_branch"); err != nil {
return fmt.Errorf("updateRepository: %w", err)
}
+ if err = repo_module.UpdateRepoSize(ctx, repo); err != nil {
+ log.Error("Failed to update size for repository: %v", err)
+ }
+
return nil
}
@@ -259,7 +263,7 @@ func CreateRepositoryDirectly(ctx context.Context, doer, owner *user_model.User,
defer func() {
if err != nil {
// we can not use the ctx because it maybe canceled or timeout
- cleanupRepository(doer, repo.ID)
+ cleanupRepository(repo.ID)
}
}()
@@ -454,8 +458,8 @@ func createRepositoryInDB(ctx context.Context, doer, u *user_model.User, repo *r
return nil
}
-func cleanupRepository(doer *user_model.User, repoID int64) {
- if errDelete := DeleteRepositoryDirectly(db.DefaultContext, doer, repoID); errDelete != nil {
+func cleanupRepository(repoID int64) {
+ if errDelete := DeleteRepositoryDirectly(db.DefaultContext, repoID); errDelete != nil {
log.Error("cleanupRepository failed: %v", errDelete)
// add system notice
if err := system_model.CreateRepositoryNotice("DeleteRepositoryDirectly failed when cleanup repository: %v", errDelete); err != nil {
diff --git a/services/repository/create_test.go b/services/repository/create_test.go
index 8e3fdf88a5..fe464c1441 100644
--- a/services/repository/create_test.go
+++ b/services/repository/create_test.go
@@ -35,7 +35,7 @@ func TestCreateRepositoryDirectly(t *testing.T) {
unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: user2.Name, Name: createdRepo.Name})
- err = DeleteRepositoryDirectly(db.DefaultContext, user2, createdRepo.ID)
+ err = DeleteRepositoryDirectly(db.DefaultContext, createdRepo.ID)
assert.NoError(t, err)
// a failed creating because some mock data
diff --git a/services/repository/delete.go b/services/repository/delete.go
index 06a980c9a8..c48d6e1d56 100644
--- a/services/repository/delete.go
+++ b/services/repository/delete.go
@@ -49,7 +49,7 @@ func deleteDBRepository(ctx context.Context, repoID int64) error {
// DeleteRepository deletes a repository for a user or organization.
// make sure if you call this func to close open sessions (sqlite will otherwise get a deadlock)
-func DeleteRepositoryDirectly(ctx context.Context, doer *user_model.User, repoID int64, ignoreOrgTeams ...bool) error {
+func DeleteRepositoryDirectly(ctx context.Context, repoID int64, ignoreOrgTeams ...bool) error {
ctx, committer, err := db.TxContext(ctx)
if err != nil {
return err
@@ -391,7 +391,7 @@ func DeleteOwnerRepositoriesDirectly(ctx context.Context, owner *user_model.User
break
}
for _, repo := range repos {
- if err := DeleteRepositoryDirectly(ctx, owner, repo.ID); err != nil {
+ if err := DeleteRepositoryDirectly(ctx, repo.ID); err != nil {
return fmt.Errorf("unable to delete repository %s for %s[%d]. Error: %w", repo.Name, owner.Name, owner.ID, err)
}
}
diff --git a/services/repository/files/diff.go b/services/repository/files/diff.go
index 0b3550452a..50d01f9d7c 100644
--- a/services/repository/files/diff.go
+++ b/services/repository/files/diff.go
@@ -29,7 +29,7 @@ func GetDiffPreview(ctx context.Context, repo *repo_model.Repository, branch, tr
}
// Add the object to the database
- objectHash, err := t.HashObject(ctx, strings.NewReader(content))
+ objectHash, err := t.HashObjectAndWrite(ctx, strings.NewReader(content))
if err != nil {
return nil, err
}
diff --git a/services/repository/files/file.go b/services/repository/files/file.go
index c4991b458d..0e1100a098 100644
--- a/services/repository/files/file.go
+++ b/services/repository/files/file.go
@@ -139,7 +139,7 @@ func CleanUploadFileName(name string) string {
// Rebase the filename
name = util.PathJoinRel(name)
// Git disallows any filenames to have a .git directory in them.
- for _, part := range strings.Split(name, "/") {
+ for part := range strings.SplitSeq(name, "/") {
if strings.ToLower(part) == ".git" {
return ""
}
diff --git a/services/repository/files/temp_repo.go b/services/repository/files/temp_repo.go
index 1cf30edc7b..c2f61c8223 100644
--- a/services/repository/files/temp_repo.go
+++ b/services/repository/files/temp_repo.go
@@ -128,7 +128,7 @@ func (t *TemporaryUploadRepository) LsFiles(ctx context.Context, filenames ...st
}
fileList := make([]string, 0, len(filenames))
- for _, line := range bytes.Split(stdOut.Bytes(), []byte{'\000'}) {
+ for line := range bytes.SplitSeq(stdOut.Bytes(), []byte{'\000'}) {
fileList = append(fileList, string(line))
}
@@ -164,8 +164,8 @@ func (t *TemporaryUploadRepository) RemoveFilesFromIndex(ctx context.Context, fi
return nil
}
-// HashObject writes the provided content to the object db and returns its hash
-func (t *TemporaryUploadRepository) HashObject(ctx context.Context, content io.Reader) (string, error) {
+// HashObjectAndWrite writes the provided content to the object db and returns its hash
+func (t *TemporaryUploadRepository) HashObjectAndWrite(ctx context.Context, content io.Reader) (string, error) {
stdOut := new(bytes.Buffer)
stdErr := new(bytes.Buffer)
diff --git a/services/repository/files/tree.go b/services/repository/files/tree.go
index 8427fcbacc..a3c3d20238 100644
--- a/services/repository/files/tree.go
+++ b/services/repository/files/tree.go
@@ -94,11 +94,7 @@ func GetTreeBySHA(ctx context.Context, repo *repo_model.Repository, gitRepo *git
if len(entries) > perPage {
tree.Truncated = true
}
- if rangeStart+perPage < len(entries) {
- rangeEnd = rangeStart + perPage
- } else {
- rangeEnd = len(entries)
- }
+ rangeEnd = min(rangeStart+perPage, len(entries))
tree.Entries = make([]api.GitEntry, rangeEnd-rangeStart)
for e := rangeStart; e < rangeEnd; e++ {
i := e - rangeStart
diff --git a/services/repository/files/update.go b/services/repository/files/update.go
index e1acf6a92f..99c1215c9f 100644
--- a/services/repository/files/update.go
+++ b/services/repository/files/update.go
@@ -8,6 +8,7 @@ import (
"fmt"
"io"
"path"
+ "slices"
"strings"
"time"
@@ -203,13 +204,7 @@ func ChangeRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use
}
// Find the file we want to delete in the index
- inFilelist := false
- for _, indexFile := range filesInIndex {
- if indexFile == file.TreePath {
- inFilelist = true
- break
- }
- }
+ inFilelist := slices.Contains(filesInIndex, file.TreePath)
if !inFilelist {
return nil, ErrRepoFileDoesNotExist{
Path: file.TreePath,
@@ -225,7 +220,7 @@ func ChangeRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use
return nil, err // Couldn't get a commit for the branch
}
- // Assigned LastCommitID in opts if it hasn't been set
+ // Assigned LastCommitID in "opts" if it hasn't been set
if opts.LastCommitID == "" {
opts.LastCommitID = commit.ID.String()
} else {
@@ -237,22 +232,21 @@ func ChangeRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use
}
for _, file := range opts.Files {
- if err := handleCheckErrors(file, commit, opts); err != nil {
+ if err = handleCheckErrors(file, commit, opts); err != nil {
return nil, err
}
}
}
- contentStore := lfs.NewContentStore()
+ lfsContentStore := lfs.NewContentStore()
for _, file := range opts.Files {
switch file.Operation {
case "create", "update", "rename":
- if err := CreateOrUpdateFile(ctx, t, file, contentStore, repo.ID, hasOldBranch); err != nil {
+ if err = CreateUpdateRenameFile(ctx, t, file, lfsContentStore, repo.ID, hasOldBranch); err != nil {
return nil, err
}
case "delete":
- // Remove the file from the index
- if err := t.RemoveFilesFromIndex(ctx, file.TreePath); err != nil {
+ if err = t.RemoveFilesFromIndex(ctx, file.TreePath); err != nil {
return nil, err
}
default:
@@ -372,13 +366,13 @@ func (err ErrSHAOrCommitIDNotProvided) Error() string {
// handles the check for various issues for ChangeRepoFiles
func handleCheckErrors(file *ChangeRepoFile, commit *git.Commit, opts *ChangeRepoFilesOptions) error {
- if file.Operation == "update" || file.Operation == "delete" {
+ if file.Operation == "update" || file.Operation == "delete" || file.Operation == "rename" {
fromEntry, err := commit.GetTreeEntryByPath(file.Options.fromTreePath)
if err != nil {
return err
}
if file.SHA != "" {
- // If a SHA was given and the SHA given doesn't match the SHA of the fromTreePath, throw error
+ // If the SHA given doesn't match the SHA of the fromTreePath, throw error
if file.SHA != fromEntry.ID.String() {
return pull_service.ErrSHADoesNotMatch{
Path: file.Options.treePath,
@@ -387,7 +381,7 @@ func handleCheckErrors(file *ChangeRepoFile, commit *git.Commit, opts *ChangeRep
}
}
} else if opts.LastCommitID != "" {
- // If a lastCommitID was given and it doesn't match the commitID of the head of the branch throw
+ // If a lastCommitID given doesn't match the branch head's commitID throw
// an error, but only if we aren't creating a new branch.
if commit.ID.String() != opts.LastCommitID && opts.OldBranch == opts.NewBranch {
if changed, err := commit.FileChangedSinceCommit(file.Options.treePath, opts.LastCommitID); err != nil {
@@ -405,13 +399,14 @@ func handleCheckErrors(file *ChangeRepoFile, commit *git.Commit, opts *ChangeRep
// haven't been made. We throw an error if one wasn't provided.
return ErrSHAOrCommitIDNotProvided{}
}
+ // FIXME: legacy hacky approach, it shouldn't prepare the "Options" in the "check" function
file.Options.executable = fromEntry.IsExecutable()
}
- if file.Operation == "create" || file.Operation == "update" {
- // For the path where this file will be created/updated, we need to make
- // sure no parts of the path are existing files or links except for the last
- // item in the path which is the file name, and that shouldn't exist IF it is
- // a new file OR is being moved to a new path.
+
+ if file.Operation == "create" || file.Operation == "update" || file.Operation == "rename" {
+ // For operation's target path, we need to make sure no parts of the path are existing files or links
+ // except for the last item in the path (which is the file name).
+ // And that shouldn't exist IF it is a new file OR is being moved to a new path.
treePathParts := strings.Split(file.Options.treePath, "/")
subTreePath := ""
for index, part := range treePathParts {
@@ -448,7 +443,7 @@ func handleCheckErrors(file *ChangeRepoFile, commit *git.Commit, opts *ChangeRep
Type: git.EntryModeTree,
}
} else if file.Options.fromTreePath != file.Options.treePath || file.Operation == "create" {
- // The entry shouldn't exist if we are creating new file or moving to a new path
+ // The entry shouldn't exist if we are creating the new file or moving to a new path
return ErrRepoFileAlreadyExists{
Path: file.Options.treePath,
}
@@ -459,8 +454,7 @@ func handleCheckErrors(file *ChangeRepoFile, commit *git.Commit, opts *ChangeRep
return nil
}
-// CreateOrUpdateFile handles creating or updating a file for ChangeRepoFiles
-func CreateOrUpdateFile(ctx context.Context, t *TemporaryUploadRepository, file *ChangeRepoFile, contentStore *lfs.ContentStore, repoID int64, hasOldBranch bool) error {
+func CreateUpdateRenameFile(ctx context.Context, t *TemporaryUploadRepository, file *ChangeRepoFile, contentStore *lfs.ContentStore, repoID int64, hasOldBranch bool) error {
// Get the two paths (might be the same if not moving) from the index if they exist
filesInIndex, err := t.LsFiles(ctx, file.TreePath, file.FromTreePath)
if err != nil {
@@ -468,11 +462,9 @@ func CreateOrUpdateFile(ctx context.Context, t *TemporaryUploadRepository, file
}
// If is a new file (not updating) then the given path shouldn't exist
if file.Operation == "create" {
- for _, indexFile := range filesInIndex {
- if indexFile == file.TreePath {
- return ErrRepoFileAlreadyExists{
- Path: file.TreePath,
- }
+ if slices.Contains(filesInIndex, file.TreePath) {
+ return ErrRepoFileAlreadyExists{
+ Path: file.TreePath,
}
}
}
@@ -481,181 +473,177 @@ func CreateOrUpdateFile(ctx context.Context, t *TemporaryUploadRepository, file
if file.Options.fromTreePath != file.Options.treePath && len(filesInIndex) > 0 {
for _, indexFile := range filesInIndex {
if indexFile == file.Options.fromTreePath {
- if err := t.RemoveFilesFromIndex(ctx, file.FromTreePath); err != nil {
+ if err = t.RemoveFilesFromIndex(ctx, file.FromTreePath); err != nil {
return err
}
}
}
}
- var oldEntry *git.TreeEntry
- // Assume that the file.ContentReader of a pure rename operation is invalid. Use the file content how it's present in
- // git instead
- if file.Operation == "rename" {
- lastCommitID, err := t.GetLastCommit(ctx)
- if err != nil {
- return err
- }
- commit, err := t.GetCommit(lastCommitID)
- if err != nil {
- return err
- }
-
- if oldEntry, err = commit.GetTreeEntryByPath(file.Options.fromTreePath); err != nil {
- return err
- }
- }
-
- var objectHash string
- var lfsPointer *lfs.Pointer
+ var writeObjectRet *writeRepoObjectRet
switch file.Operation {
case "create", "update":
- objectHash, lfsPointer, err = createOrUpdateFileHash(ctx, t, file, hasOldBranch)
+ writeObjectRet, err = writeRepoObjectForCreateOrUpdate(ctx, t, file)
case "rename":
- objectHash, lfsPointer, err = renameFileHash(ctx, t, oldEntry, file)
+ writeObjectRet, err = writeRepoObjectForRename(ctx, t, file)
+ default:
+ return util.NewInvalidArgumentErrorf("unknown file modification operation: '%s'", file.Operation)
}
if err != nil {
return err
}
- // Add the object to the index
- if file.Options.executable {
- if err := t.AddObjectToIndex(ctx, "100755", objectHash, file.Options.treePath); err != nil {
- return err
- }
- } else {
- if err := t.AddObjectToIndex(ctx, "100644", objectHash, file.Options.treePath); err != nil {
- return err
- }
+ // Add the object to the index, the "file.Options.executable" is set in handleCheckErrors by the caller (legacy hacky approach)
+ if err = t.AddObjectToIndex(ctx, util.Iif(file.Options.executable, "100755", "100644"), writeObjectRet.ObjectHash, file.Options.treePath); err != nil {
+ return err
}
- if lfsPointer != nil {
- // We have an LFS object - create it
- lfsMetaObject, err := git_model.NewLFSMetaObject(ctx, repoID, *lfsPointer)
- if err != nil {
- return err
- }
- exist, err := contentStore.Exists(lfsMetaObject.Pointer)
- if err != nil {
- return err
- }
- if !exist {
- var lfsContentReader io.Reader
- if file.Operation != "rename" {
- if _, err := file.ContentReader.Seek(0, io.SeekStart); err != nil {
- return err
- }
- lfsContentReader = file.ContentReader
- } else {
- if lfsContentReader, err = oldEntry.Blob().DataAsync(); err != nil {
- return err
- }
- defer lfsContentReader.(io.ReadCloser).Close()
- }
+ if writeObjectRet.LfsContent == nil {
+ return nil // No LFS pointer, so nothing to do
+ }
+ defer writeObjectRet.LfsContent.Close()
- if err := contentStore.Put(lfsMetaObject.Pointer, lfsContentReader); err != nil {
- if _, err2 := git_model.RemoveLFSMetaObjectByOid(ctx, repoID, lfsMetaObject.Oid); err2 != nil {
- return fmt.Errorf("unable to remove failed inserted LFS object %s: %v (Prev Error: %w)", lfsMetaObject.Oid, err2, err)
- }
- return err
- }
+ // Now we must store the content into an LFS object
+ lfsMetaObject, err := git_model.NewLFSMetaObject(ctx, repoID, writeObjectRet.LfsPointer)
+ if err != nil {
+ return err
+ }
+ if exist, err := contentStore.Exists(lfsMetaObject.Pointer); err != nil {
+ return err
+ } else if exist {
+ return nil
+ }
+
+ err = contentStore.Put(lfsMetaObject.Pointer, writeObjectRet.LfsContent)
+ if err != nil {
+ if _, errRemove := git_model.RemoveLFSMetaObjectByOid(ctx, repoID, lfsMetaObject.Oid); errRemove != nil {
+ return fmt.Errorf("unable to remove failed inserted LFS object %s: %v (Prev Error: %w)", lfsMetaObject.Oid, errRemove, err)
}
}
+ return err
+}
- return nil
+func checkIsLfsFileInGitAttributes(ctx context.Context, t *TemporaryUploadRepository, paths []string) (ret []bool, err error) {
+ attributesMap, err := attribute.CheckAttributes(ctx, t.gitRepo, "" /* use temp repo's working dir */, attribute.CheckAttributeOpts{
+ Attributes: []string{attribute.Filter},
+ Filenames: paths,
+ })
+ if err != nil {
+ return nil, err
+ }
+ for _, p := range paths {
+ isLFSFile := attributesMap[p] != nil && attributesMap[p].Get(attribute.Filter).ToString().Value() == "lfs"
+ ret = append(ret, isLFSFile)
+ }
+ return ret, nil
+}
+
+type writeRepoObjectRet struct {
+ ObjectHash string
+ LfsContent io.ReadCloser // if not nil, then the caller should store its content in LfsPointer, then close it
+ LfsPointer lfs.Pointer
}
-func createOrUpdateFileHash(ctx context.Context, t *TemporaryUploadRepository, file *ChangeRepoFile, hasOldBranch bool) (string, *lfs.Pointer, error) {
+// writeRepoObjectForCreateOrUpdate hashes the git object for create or update operations
+func writeRepoObjectForCreateOrUpdate(ctx context.Context, t *TemporaryUploadRepository, file *ChangeRepoFile) (ret *writeRepoObjectRet, err error) {
+ ret = &writeRepoObjectRet{}
treeObjectContentReader := file.ContentReader
- var lfsPointer *lfs.Pointer
- if setting.LFS.StartServer && hasOldBranch {
- // Check there is no way this can return multiple infos
- attributesMap, err := attribute.CheckAttributes(ctx, t.gitRepo, "" /* use temp repo's working dir */, attribute.CheckAttributeOpts{
- Attributes: []string{attribute.Filter},
- Filenames: []string{file.Options.treePath},
- })
+ if setting.LFS.StartServer {
+ checkIsLfsFiles, err := checkIsLfsFileInGitAttributes(ctx, t, []string{file.Options.treePath})
if err != nil {
- return "", nil, err
+ return nil, err
}
-
- if attributesMap[file.Options.treePath] != nil && attributesMap[file.Options.treePath].Get(attribute.Filter).ToString().Value() == "lfs" {
- // OK so we are supposed to LFS this data!
- pointer, err := lfs.GeneratePointer(treeObjectContentReader)
+ if checkIsLfsFiles[0] {
+ // OK, so we are supposed to LFS this data!
+ ret.LfsPointer, err = lfs.GeneratePointer(file.ContentReader)
if err != nil {
- return "", nil, err
+ return nil, err
}
- lfsPointer = &pointer
- treeObjectContentReader = strings.NewReader(pointer.StringContent())
+ if _, err = file.ContentReader.Seek(0, io.SeekStart); err != nil {
+ return nil, err
+ }
+ ret.LfsContent = io.NopCloser(file.ContentReader)
+ treeObjectContentReader = strings.NewReader(ret.LfsPointer.StringContent())
}
}
- // Add the object to the database
- objectHash, err := t.HashObject(ctx, treeObjectContentReader)
+ ret.ObjectHash, err = t.HashObjectAndWrite(ctx, treeObjectContentReader)
if err != nil {
- return "", nil, err
+ return nil, err
}
-
- return objectHash, lfsPointer, nil
+ return ret, nil
}
-func renameFileHash(ctx context.Context, t *TemporaryUploadRepository, oldEntry *git.TreeEntry, file *ChangeRepoFile) (string, *lfs.Pointer, error) {
- if setting.LFS.StartServer {
- attributesMap, err := attribute.CheckAttributes(ctx, t.gitRepo, "" /* use temp repo's working dir */, attribute.CheckAttributeOpts{
- Attributes: []string{attribute.Filter},
- Filenames: []string{file.Options.treePath, file.Options.fromTreePath},
- })
- if err != nil {
- return "", nil, err
- }
+// writeRepoObjectForRename the same as writeRepoObjectForCreateOrUpdate buf for "rename"
+func writeRepoObjectForRename(ctx context.Context, t *TemporaryUploadRepository, file *ChangeRepoFile) (ret *writeRepoObjectRet, err error) {
+ lastCommitID, err := t.GetLastCommit(ctx)
+ if err != nil {
+ return nil, err
+ }
+ commit, err := t.GetCommit(lastCommitID)
+ if err != nil {
+ return nil, err
+ }
+ oldEntry, err := commit.GetTreeEntryByPath(file.Options.fromTreePath)
+ if err != nil {
+ return nil, err
+ }
- oldIsLfs := attributesMap[file.Options.fromTreePath] != nil && attributesMap[file.Options.fromTreePath].Get(attribute.Filter).ToString().Value() == "lfs"
- newIsLfs := attributesMap[file.Options.treePath] != nil && attributesMap[file.Options.treePath].Get(attribute.Filter).ToString().Value() == "lfs"
+ ret = &writeRepoObjectRet{ObjectHash: oldEntry.ID.String()}
+ if !setting.LFS.StartServer {
+ return ret, nil
+ }
- // If the old and new paths are both in lfs or both not in lfs, the object hash of the old file can be used directly
- // as the object doesn't change
- if oldIsLfs == newIsLfs {
- return oldEntry.ID.String(), nil, nil
- }
+ checkIsLfsFiles, err := checkIsLfsFileInGitAttributes(ctx, t, []string{file.Options.fromTreePath, file.Options.treePath})
+ if err != nil {
+ return nil, err
+ }
+ oldIsLfs, newIsLfs := checkIsLfsFiles[0], checkIsLfsFiles[1]
+
+ // If the old and new paths are both in lfs or both not in lfs, the object hash of the old file can be used directly
+ // as the object doesn't change
+ if oldIsLfs == newIsLfs {
+ return ret, nil
+ }
- oldEntryReader, err := oldEntry.Blob().DataAsync()
+ oldEntryBlobPointerBy := func(f func(r io.Reader) (lfs.Pointer, error)) (lfsPointer lfs.Pointer, err error) {
+ r, err := oldEntry.Blob().DataAsync()
if err != nil {
- return "", nil, err
+ return lfsPointer, err
}
- defer oldEntryReader.Close()
+ defer r.Close()
+ return f(r)
+ }
- var treeObjectContentReader io.Reader
- var lfsPointer *lfs.Pointer
- // If the old path is in lfs but the new isn't, read the content from lfs and add it as normal git object
- // If the new path is in lfs but the old isn't, read the content from the git object and generate a lfs
- // pointer of it
- if oldIsLfs {
- pointer, err := lfs.ReadPointer(oldEntryReader)
- if err != nil {
- return "", nil, err
- }
- treeObjectContentReader, err = lfs.ReadMetaObject(pointer)
- if err != nil {
- return "", nil, err
- }
- defer treeObjectContentReader.(io.ReadCloser).Close()
- } else {
- pointer, err := lfs.GeneratePointer(oldEntryReader)
- if err != nil {
- return "", nil, err
- }
- treeObjectContentReader = strings.NewReader(pointer.StringContent())
- lfsPointer = &pointer
+ var treeObjectContentReader io.ReadCloser
+ if oldIsLfs {
+ // If the old is in lfs but the new isn't, read the content from lfs and add it as a normal git object
+ pointer, err := oldEntryBlobPointerBy(lfs.ReadPointer)
+ if err != nil {
+ return nil, err
}
-
- // Add the object to the database
- objectID, err := t.HashObject(ctx, treeObjectContentReader)
+ treeObjectContentReader, err = lfs.ReadMetaObject(pointer)
if err != nil {
- return "", nil, err
+ return nil, err
}
- return objectID, lfsPointer, nil
+ defer treeObjectContentReader.Close()
+ } else {
+ // If the new is in lfs but the old isn't, read the content from the git object and generate a lfs pointer of it
+ ret.LfsPointer, err = oldEntryBlobPointerBy(lfs.GeneratePointer)
+ if err != nil {
+ return nil, err
+ }
+ ret.LfsContent, err = oldEntry.Blob().DataAsync()
+ if err != nil {
+ return nil, err
+ }
+ treeObjectContentReader = io.NopCloser(strings.NewReader(ret.LfsPointer.StringContent()))
}
-
- return oldEntry.ID.String(), nil, nil
+ ret.ObjectHash, err = t.HashObjectAndWrite(ctx, treeObjectContentReader)
+ if err != nil {
+ return nil, err
+ }
+ return ret, nil
}
// VerifyBranchProtection verify the branch protection for modifying the given treePath on the given branch
diff --git a/services/repository/files/upload.go b/services/repository/files/upload.go
index 68a071cd28..b004e3cc4c 100644
--- a/services/repository/files/upload.go
+++ b/services/repository/files/upload.go
@@ -201,10 +201,10 @@ func copyUploadedLFSFileIntoRepository(ctx context.Context, info *uploadInfo, at
info.lfsMetaObject = &git_model.LFSMetaObject{Pointer: pointer, RepositoryID: t.repo.ID}
- if objectHash, err = t.HashObject(ctx, strings.NewReader(pointer.StringContent())); err != nil {
+ if objectHash, err = t.HashObjectAndWrite(ctx, strings.NewReader(pointer.StringContent())); err != nil {
return err
}
- } else if objectHash, err = t.HashObject(ctx, file); err != nil {
+ } else if objectHash, err = t.HashObjectAndWrite(ctx, file); err != nil {
return err
}
diff --git a/services/repository/fork.go b/services/repository/fork.go
index bd1554f163..8bd3498b17 100644
--- a/services/repository/fork.go
+++ b/services/repository/fork.go
@@ -124,7 +124,7 @@ func ForkRepository(ctx context.Context, doer, owner *user_model.User, opts Fork
defer func() {
if err != nil {
// we can not use the ctx because it maybe canceled or timeout
- cleanupRepository(doer, repo.ID)
+ cleanupRepository(repo.ID)
}
}()
@@ -209,7 +209,7 @@ func ForkRepository(ctx context.Context, doer, owner *user_model.User, opts Fork
// ConvertForkToNormalRepository convert the provided repo from a forked repo to normal repo
func ConvertForkToNormalRepository(ctx context.Context, repo *repo_model.Repository) error {
- err := db.WithTx(ctx, func(ctx context.Context) error {
+ return db.WithTx(ctx, func(ctx context.Context) error {
repo, err := repo_model.GetRepositoryByID(ctx, repo.ID)
if err != nil {
return err
@@ -226,16 +226,8 @@ func ConvertForkToNormalRepository(ctx context.Context, repo *repo_model.Reposit
repo.IsFork = false
repo.ForkID = 0
-
- if err := updateRepository(ctx, repo, false); err != nil {
- log.Error("Unable to update repository %-v whilst converting from fork. Error: %v", repo, err)
- return err
- }
-
- return nil
+ return repo_model.UpdateRepositoryColsNoAutoTime(ctx, repo, "is_fork", "fork_id")
})
-
- return err
}
type findForksOptions struct {
diff --git a/services/repository/fork_test.go b/services/repository/fork_test.go
index 35c6effca5..5375f79028 100644
--- a/services/repository/fork_test.go
+++ b/services/repository/fork_test.go
@@ -69,7 +69,7 @@ func TestForkRepositoryCleanup(t *testing.T) {
assert.NoError(t, err)
assert.True(t, exist)
- err = DeleteRepositoryDirectly(db.DefaultContext, user2, fork.ID)
+ err = DeleteRepositoryDirectly(db.DefaultContext, fork.ID)
assert.NoError(t, err)
// a failed creating because some mock data
diff --git a/services/repository/generate.go b/services/repository/generate.go
index 77a43b4e39..867b5d7855 100644
--- a/services/repository/generate.go
+++ b/services/repository/generate.go
@@ -253,43 +253,35 @@ func generateRepoCommit(ctx context.Context, repo, templateRepo, generateRepo *r
return initRepoCommit(ctx, tmpDir, repo, repo.Owner, defaultBranch)
}
-func generateGitContent(ctx context.Context, repo, templateRepo, generateRepo *repo_model.Repository) (err error) {
- tmpDir, cleanup, err := setting.AppDataTempDir("git-repo-content").MkdirTempRandom("gitea-" + repo.Name)
+// GenerateGitContent generates git content from a template repository
+func GenerateGitContent(ctx context.Context, templateRepo, generateRepo *repo_model.Repository) (err error) {
+ tmpDir, cleanup, err := setting.AppDataTempDir("git-repo-content").MkdirTempRandom("gitea-" + generateRepo.Name)
if err != nil {
- return fmt.Errorf("failed to create temp dir for repository %s: %w", repo.FullName(), err)
+ return fmt.Errorf("failed to create temp dir for repository %s: %w", generateRepo.FullName(), err)
}
defer cleanup()
- if err = generateRepoCommit(ctx, repo, templateRepo, generateRepo, tmpDir); err != nil {
+ if err = generateRepoCommit(ctx, generateRepo, templateRepo, generateRepo, tmpDir); err != nil {
return fmt.Errorf("generateRepoCommit: %w", err)
}
// re-fetch repo
- if repo, err = repo_model.GetRepositoryByID(ctx, repo.ID); err != nil {
+ if generateRepo, err = repo_model.GetRepositoryByID(ctx, generateRepo.ID); err != nil {
return fmt.Errorf("getRepositoryByID: %w", err)
}
// if there was no default branch supplied when generating the repo, use the default one from the template
- if strings.TrimSpace(repo.DefaultBranch) == "" {
- repo.DefaultBranch = templateRepo.DefaultBranch
+ if strings.TrimSpace(generateRepo.DefaultBranch) == "" {
+ generateRepo.DefaultBranch = templateRepo.DefaultBranch
}
- if err = gitrepo.SetDefaultBranch(ctx, repo, repo.DefaultBranch); err != nil {
+ if err = gitrepo.SetDefaultBranch(ctx, generateRepo, generateRepo.DefaultBranch); err != nil {
return fmt.Errorf("setDefaultBranch: %w", err)
}
- if err = UpdateRepository(ctx, repo, false); err != nil {
+ if err = repo_model.UpdateRepositoryColsNoAutoTime(ctx, generateRepo, "default_branch"); err != nil {
return fmt.Errorf("updateRepository: %w", err)
}
- return nil
-}
-
-// GenerateGitContent generates git content from a template repository
-func GenerateGitContent(ctx context.Context, templateRepo, generateRepo *repo_model.Repository) error {
- if err := generateGitContent(ctx, generateRepo, templateRepo, generateRepo); err != nil {
- return err
- }
-
if err := repo_module.UpdateRepoSize(ctx, generateRepo); err != nil {
return fmt.Errorf("failed to update size for repository: %w", err)
}
diff --git a/services/repository/gitgraph/graph_models.go b/services/repository/gitgraph/graph_models.go
index 31379410b2..02b0268cd9 100644
--- a/services/repository/gitgraph/graph_models.go
+++ b/services/repository/gitgraph/graph_models.go
@@ -232,8 +232,8 @@ func newRefsFromRefNames(refNames []byte) []git.Reference {
continue
}
refName := string(refNameBytes)
- if strings.HasPrefix(refName, "tag: ") {
- refName = strings.TrimPrefix(refName, "tag: ")
+ if after, ok := strings.CutPrefix(refName, "tag: "); ok {
+ refName = after
} else {
refName = strings.TrimPrefix(refName, "HEAD -> ")
}
diff --git a/services/repository/gitgraph/graph_test.go b/services/repository/gitgraph/graph_test.go
index 4c48b94aa2..93fa1aec6a 100644
--- a/services/repository/gitgraph/graph_test.go
+++ b/services/repository/gitgraph/graph_test.go
@@ -6,6 +6,7 @@ package gitgraph
import (
"bytes"
"fmt"
+ "slices"
"strings"
"testing"
@@ -117,13 +118,7 @@ func TestReleaseUnusedColors(t *testing.T) {
if parser.firstAvailable == -1 {
// All in use
for _, color := range parser.availableColors {
- found := false
- for _, oldColor := range parser.oldColors {
- if oldColor == color {
- found = true
- break
- }
- }
+ found := slices.Contains(parser.oldColors, color)
if !found {
t.Errorf("In testcase:\n%d\t%d\t%d %d =>\n%d\t%d\t%d %d: %d should be available but is not",
testcase.availableColors,
@@ -141,13 +136,7 @@ func TestReleaseUnusedColors(t *testing.T) {
// Some in use
for i := parser.firstInUse; i != parser.firstAvailable; i = (i + 1) % len(parser.availableColors) {
color := parser.availableColors[i]
- found := false
- for _, oldColor := range parser.oldColors {
- if oldColor == color {
- found = true
- break
- }
- }
+ found := slices.Contains(parser.oldColors, color)
if !found {
t.Errorf("In testcase:\n%d\t%d\t%d %d =>\n%d\t%d\t%d %d: %d should be available but is not",
testcase.availableColors,
@@ -163,13 +152,7 @@ func TestReleaseUnusedColors(t *testing.T) {
}
for i := parser.firstAvailable; i != parser.firstInUse; i = (i + 1) % len(parser.availableColors) {
color := parser.availableColors[i]
- found := false
- for _, oldColor := range parser.oldColors {
- if oldColor == color {
- found = true
- break
- }
- }
+ found := slices.Contains(parser.oldColors, color)
if found {
t.Errorf("In testcase:\n%d\t%d\t%d %d =>\n%d\t%d\t%d %d: %d should not be available but is",
testcase.availableColors,
diff --git a/services/repository/migrate.go b/services/repository/migrate.go
index 0859158b89..0a3dc45339 100644
--- a/services/repository/migrate.go
+++ b/services/repository/migrate.go
@@ -220,10 +220,14 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User,
}
repo.IsMirror = true
- if err = UpdateRepository(ctx, repo, false); err != nil {
+ if err = repo_model.UpdateRepositoryColsNoAutoTime(ctx, repo, "num_watches", "is_empty", "default_branch", "default_wiki_branch", "is_mirror"); err != nil {
return nil, err
}
+ if err = repo_module.UpdateRepoSize(ctx, repo); err != nil {
+ log.Error("Failed to update size for repository: %v", err)
+ }
+
// this is necessary for sync local tags from remote
configName := fmt.Sprintf("remote.%s.fetch", mirrorModel.GetRemoteName())
if stdout, _, err := git.NewCommand("config").
diff --git a/services/repository/push.go b/services/repository/push.go
index 3735c5f3a4..af3c873d15 100644
--- a/services/repository/push.go
+++ b/services/repository/push.go
@@ -232,7 +232,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error {
}
if len(addTags)+len(delTags) > 0 {
- if err := PushUpdateAddDeleteTags(ctx, repo, gitRepo, addTags, delTags); err != nil {
+ if err := PushUpdateAddDeleteTags(ctx, repo, gitRepo, pusher, addTags, delTags); err != nil {
return fmt.Errorf("PushUpdateAddDeleteTags: %w", err)
}
}
@@ -342,17 +342,17 @@ func pushDeleteBranch(ctx context.Context, repo *repo_model.Repository, pusher *
}
// PushUpdateAddDeleteTags updates a number of added and delete tags
-func PushUpdateAddDeleteTags(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, addTags, delTags []string) error {
+func PushUpdateAddDeleteTags(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, pusher *user_model.User, addTags, delTags []string) error {
return db.WithTx(ctx, func(ctx context.Context) error {
if err := repo_model.PushUpdateDeleteTags(ctx, repo, delTags); err != nil {
return err
}
- return pushUpdateAddTags(ctx, repo, gitRepo, addTags)
+ return pushUpdateAddTags(ctx, repo, gitRepo, pusher, addTags)
})
}
// pushUpdateAddTags updates a number of add tags
-func pushUpdateAddTags(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, tags []string) error {
+func pushUpdateAddTags(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, pusher *user_model.User, tags []string) error {
if len(tags) == 0 {
return nil
}
@@ -378,8 +378,6 @@ func pushUpdateAddTags(ctx context.Context, repo *repo_model.Repository, gitRepo
newReleases := make([]*repo_model.Release, 0, len(lowerTags)-len(relMap))
- emailToUser := make(map[string]*user_model.User)
-
for i, lowerTag := range lowerTags {
tag, err := gitRepo.GetTag(tags[i])
if err != nil {
@@ -397,21 +395,9 @@ func pushUpdateAddTags(ctx context.Context, repo *repo_model.Repository, gitRepo
if sig == nil {
sig = commit.Committer
}
- var author *user_model.User
- createdAt := time.Unix(1, 0)
+ createdAt := time.Unix(1, 0)
if sig != nil {
- var ok bool
- author, ok = emailToUser[sig.Email]
- if !ok {
- author, err = user_model.GetUserByEmail(ctx, sig.Email)
- if err != nil && !user_model.IsErrUserNotExist(err) {
- return fmt.Errorf("GetUserByEmail: %w", err)
- }
- if author != nil {
- emailToUser[sig.Email] = author
- }
- }
createdAt = sig.When
}
@@ -435,11 +421,9 @@ func pushUpdateAddTags(ctx context.Context, repo *repo_model.Repository, gitRepo
IsDraft: false,
IsPrerelease: false,
IsTag: true,
+ PublisherID: pusher.ID,
CreatedUnix: timeutil.TimeStamp(createdAt.Unix()),
}
- if author != nil {
- rel.PublisherID = author.ID
- }
newReleases = append(newReleases, rel)
} else {
@@ -448,12 +432,10 @@ func pushUpdateAddTags(ctx context.Context, repo *repo_model.Repository, gitRepo
if rel.IsTag {
rel.Title = parts[0]
rel.Note = note
- if author != nil {
- rel.PublisherID = author.ID
- }
} else {
rel.IsDraft = false
}
+ rel.PublisherID = pusher.ID
if err = repo_model.UpdateRelease(ctx, rel); err != nil {
return fmt.Errorf("Update: %w", err)
}
diff --git a/services/repository/repository.go b/services/repository/repository.go
index 739ef1ec38..e574dc6c01 100644
--- a/services/repository/repository.go
+++ b/services/repository/repository.go
@@ -69,7 +69,7 @@ func DeleteRepository(ctx context.Context, doer *user_model.User, repo *repo_mod
notify_service.DeleteRepository(ctx, doer, repo)
}
- return DeleteRepositoryDirectly(ctx, doer, repo.ID)
+ return DeleteRepositoryDirectly(ctx, repo.ID)
}
// PushCreateRepo creates a repository when a new repository is pushed to an appropriate namespace
@@ -127,9 +127,42 @@ func UpdateRepository(ctx context.Context, repo *repo_model.Repository, visibili
func MakeRepoPublic(ctx context.Context, repo *repo_model.Repository) (err error) {
return db.WithTx(ctx, func(ctx context.Context) error {
repo.IsPrivate = false
- if err = updateRepository(ctx, repo, true); err != nil {
- return fmt.Errorf("MakeRepoPublic: %w", err)
+ if err := repo_model.UpdateRepositoryColsNoAutoTime(ctx, repo, "is_private"); err != nil {
+ return err
+ }
+
+ if err = repo.LoadOwner(ctx); err != nil {
+ return fmt.Errorf("LoadOwner: %w", err)
}
+ if repo.Owner.IsOrganization() {
+ // Organization repository need to recalculate access table when visibility is changed.
+ if err = access_model.RecalculateTeamAccesses(ctx, repo, 0); err != nil {
+ return fmt.Errorf("recalculateTeamAccesses: %w", err)
+ }
+ }
+
+ // Create/Remove git-daemon-export-ok for git-daemon...
+ if err := checkDaemonExportOK(ctx, repo); err != nil {
+ return err
+ }
+
+ forkRepos, err := repo_model.GetRepositoriesByForkID(ctx, repo.ID)
+ if err != nil {
+ return fmt.Errorf("getRepositoriesByForkID: %w", err)
+ }
+
+ if repo.Owner.Visibility != structs.VisibleTypePrivate {
+ for i := range forkRepos {
+ if err = MakeRepoPublic(ctx, forkRepos[i]); err != nil {
+ return fmt.Errorf("MakeRepoPublic[%d]: %w", forkRepos[i].ID, err)
+ }
+ }
+ }
+
+ // If visibility is changed, we need to update the issue indexer.
+ // Since the data in the issue indexer have field to indicate if the repo is public or not.
+ issue_indexer.UpdateRepoIndexer(ctx, repo.ID)
+
return nil
})
}
@@ -137,9 +170,51 @@ func MakeRepoPublic(ctx context.Context, repo *repo_model.Repository) (err error
func MakeRepoPrivate(ctx context.Context, repo *repo_model.Repository) (err error) {
return db.WithTx(ctx, func(ctx context.Context) error {
repo.IsPrivate = true
- if err = updateRepository(ctx, repo, true); err != nil {
- return fmt.Errorf("MakeRepoPrivate: %w", err)
+ if err := repo_model.UpdateRepositoryColsNoAutoTime(ctx, repo, "is_private"); err != nil {
+ return err
+ }
+
+ if err = repo.LoadOwner(ctx); err != nil {
+ return fmt.Errorf("LoadOwner: %w", err)
}
+ if repo.Owner.IsOrganization() {
+ // Organization repository need to recalculate access table when visibility is changed.
+ if err = access_model.RecalculateTeamAccesses(ctx, repo, 0); err != nil {
+ return fmt.Errorf("recalculateTeamAccesses: %w", err)
+ }
+ }
+
+ // If repo has become private, we need to set its actions to private.
+ _, err = db.GetEngine(ctx).Where("repo_id = ?", repo.ID).Cols("is_private").Update(&activities_model.Action{
+ IsPrivate: true,
+ })
+ if err != nil {
+ return err
+ }
+
+ if err = repo_model.ClearRepoStars(ctx, repo.ID); err != nil {
+ return err
+ }
+
+ // Create/Remove git-daemon-export-ok for git-daemon...
+ if err := checkDaemonExportOK(ctx, repo); err != nil {
+ return err
+ }
+
+ forkRepos, err := repo_model.GetRepositoriesByForkID(ctx, repo.ID)
+ if err != nil {
+ return fmt.Errorf("getRepositoriesByForkID: %w", err)
+ }
+ for i := range forkRepos {
+ if err = MakeRepoPrivate(ctx, forkRepos[i]); err != nil {
+ return fmt.Errorf("MakeRepoPrivate[%d]: %w", forkRepos[i].ID, err)
+ }
+ }
+
+ // If visibility is changed, we need to update the issue indexer.
+ // Since the data in the issue indexer have field to indicate if the repo is public or not.
+ issue_indexer.UpdateRepoIndexer(ctx, repo.ID)
+
return nil
})
}
diff --git a/services/repository/template.go b/services/repository/template.go
index 621bd95cb1..6906a60083 100644
--- a/services/repository/template.go
+++ b/services/repository/template.go
@@ -102,7 +102,7 @@ func GenerateRepository(ctx context.Context, doer, owner *user_model.User, templ
defer func() {
if err != nil {
// we can not use the ctx because it maybe canceled or timeout
- cleanupRepository(doer, generateRepo.ID)
+ cleanupRepository(generateRepo.ID)
}
}()
diff --git a/services/webtheme/webtheme.go b/services/webtheme/webtheme.go
index 58aea3bc74..4e89d6dbac 100644
--- a/services/webtheme/webtheme.go
+++ b/services/webtheme/webtheme.go
@@ -70,11 +70,11 @@ func parseThemeMetaInfoToMap(cssContent string) map[string]string {
m := map[string]string{}
for _, item := range matchedItems {
v := item[3]
- if strings.HasPrefix(v, `"`) {
- v = strings.TrimSuffix(strings.TrimPrefix(v, `"`), `"`)
+ if after, ok := strings.CutPrefix(v, `"`); ok {
+ v = strings.TrimSuffix(after, `"`)
v = strings.ReplaceAll(v, `\"`, `"`)
- } else if strings.HasPrefix(v, `'`) {
- v = strings.TrimSuffix(strings.TrimPrefix(v, `'`), `'`)
+ } else if after, ok := strings.CutPrefix(v, `'`); ok {
+ v = strings.TrimSuffix(after, `'`)
v = strings.ReplaceAll(v, `\'`, `'`)
}
m[item[2]] = v
diff --git a/services/wiki/wiki_test.go b/services/wiki/wiki_test.go
index f441c2939b..6ea3ca9c1b 100644
--- a/services/wiki/wiki_test.go
+++ b/services/wiki/wiki_test.go
@@ -116,9 +116,9 @@ func TestGitPathToWebPath(t *testing.T) {
func TestUserWebGitPathConsistency(t *testing.T) {
maxLen := 20
b := make([]byte, maxLen)
- for i := 0; i < 1000; i++ {
+ for range 1000 {
l := rand.Intn(maxLen)
- for j := 0; j < l; j++ {
+ for j := range l {
r := rand.Intn(0x80-0x20) + 0x20
b[j] = byte(r)
}