code.gitea.io/gitea@v1.22.3/services/doctor/repository.go (about) 1 // Copyright 2023 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package doctor 5 6 import ( 7 "context" 8 9 "code.gitea.io/gitea/models/db" 10 user_model "code.gitea.io/gitea/models/user" 11 "code.gitea.io/gitea/modules/log" 12 "code.gitea.io/gitea/modules/storage" 13 repo_service "code.gitea.io/gitea/services/repository" 14 15 "xorm.io/builder" 16 ) 17 18 func handleDeleteOrphanedRepos(ctx context.Context, logger log.Logger, autofix bool) error { 19 test := &consistencyCheck{ 20 Name: "Repos with no existing owner", 21 Counter: countOrphanedRepos, 22 Fixer: deleteOrphanedRepos, 23 FixedMessage: "Deleted all content related to orphaned repos", 24 } 25 return test.Run(ctx, logger, autofix) 26 } 27 28 // countOrphanedRepos count repository where user of owner_id do not exist 29 func countOrphanedRepos(ctx context.Context) (int64, error) { 30 return db.CountOrphanedObjects(ctx, "repository", "user", "repository.owner_id=`user`.id") 31 } 32 33 // deleteOrphanedRepos delete repository where user of owner_id do not exist 34 func deleteOrphanedRepos(ctx context.Context) (int64, error) { 35 if err := storage.Init(); err != nil { 36 return 0, err 37 } 38 39 batchSize := db.MaxBatchInsertSize("repository") 40 e := db.GetEngine(ctx) 41 var deleted int64 42 adminUser := &user_model.User{IsAdmin: true} 43 44 for { 45 select { 46 case <-ctx.Done(): 47 return deleted, ctx.Err() 48 default: 49 var ids []int64 50 if err := e.Table("`repository`"). 51 Join("LEFT", "`user`", "repository.owner_id=`user`.id"). 52 Where(builder.IsNull{"`user`.id"}). 53 Select("`repository`.id").Limit(batchSize).Find(&ids); err != nil { 54 return deleted, err 55 } 56 57 // if we don't get ids we have deleted them all 58 if len(ids) == 0 { 59 return deleted, nil 60 } 61 62 for _, id := range ids { 63 if err := repo_service.DeleteRepositoryDirectly(ctx, adminUser, id, true); err != nil { 64 return deleted, err 65 } 66 deleted++ 67 } 68 } 69 } 70 } 71 72 func init() { 73 Register(&Check{ 74 Title: "Deleted all content related to orphaned repos", 75 Name: "delete-orphaned-repos", 76 IsDefault: false, 77 Run: handleDeleteOrphanedRepos, 78 Priority: 4, 79 }) 80 }