mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 16:40:24 +08:00 
			
		
		
		
	Add doctor dbconsistency fix to delete repos with no owner (#27290)
to address #27273 replace #24873
This commit is contained in:
		
							
								
								
									
										70
									
								
								modules/doctor/repository.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								modules/doctor/repository.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,70 @@
 | 
				
			|||||||
 | 
					// Copyright 2023 The Gitea Authors. All rights reserved.
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: MIT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package doctor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/models/db"
 | 
				
			||||||
 | 
						user_model "code.gitea.io/gitea/models/user"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/log"
 | 
				
			||||||
 | 
						repo_service "code.gitea.io/gitea/services/repository"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"xorm.io/builder"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func handleDeleteOrphanedRepos(ctx context.Context, logger log.Logger, autofix bool) error {
 | 
				
			||||||
 | 
						test := &consistencyCheck{
 | 
				
			||||||
 | 
							Name:         "Repos with no existing owner",
 | 
				
			||||||
 | 
							Counter:      countOrphanedRepos,
 | 
				
			||||||
 | 
							Fixer:        deleteOrphanedRepos,
 | 
				
			||||||
 | 
							FixedMessage: "Deleted all content related to orphaned repos",
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return test.Run(ctx, logger, autofix)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// countOrphanedRepos count repository where user of owner_id do not exist
 | 
				
			||||||
 | 
					func countOrphanedRepos(ctx context.Context) (int64, error) {
 | 
				
			||||||
 | 
						return db.CountOrphanedObjects(ctx, "repository", "user", "repository.owner_id=user.id")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// deleteOrphanedRepos delete repository where user of owner_id do not exist
 | 
				
			||||||
 | 
					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 {
 | 
				
			||||||
 | 
							var ids []int64
 | 
				
			||||||
 | 
							if err := e.Table("`repository`").
 | 
				
			||||||
 | 
								Join("LEFT", "`user`", "repository.owner_id=user.id").
 | 
				
			||||||
 | 
								Where(builder.IsNull{"`user`.id"}).
 | 
				
			||||||
 | 
								Select("`repository`.id").Limit(batchSize).Find(&ids); err != nil {
 | 
				
			||||||
 | 
								return deleted, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// if we don't get ids we have deleted them all
 | 
				
			||||||
 | 
							if len(ids) == 0 {
 | 
				
			||||||
 | 
								return deleted, nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for _, id := range ids {
 | 
				
			||||||
 | 
								if err := repo_service.DeleteRepositoryDirectly(ctx, adminUser, id, true); err != nil {
 | 
				
			||||||
 | 
									return deleted, err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								deleted++
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func init() {
 | 
				
			||||||
 | 
						Register(&Check{
 | 
				
			||||||
 | 
							Title:     "Deleted all content related to orphaned repos",
 | 
				
			||||||
 | 
							Name:      "delete-orphaned-repos",
 | 
				
			||||||
 | 
							IsDefault: false,
 | 
				
			||||||
 | 
							Run:       handleDeleteOrphanedRepos,
 | 
				
			||||||
 | 
							Priority:  4,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -33,7 +33,7 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// DeleteRepository deletes a repository for a user or organization.
 | 
					// 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)
 | 
					// 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) error {
 | 
					func DeleteRepositoryDirectly(ctx context.Context, doer *user_model.User, repoID int64, ignoreOrgTeams ...bool) error {
 | 
				
			||||||
	ctx, committer, err := db.TxContext(ctx)
 | 
						ctx, committer, err := db.TxContext(ctx)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
@@ -65,10 +65,13 @@ func DeleteRepositoryDirectly(ctx context.Context, doer *user_model.User, repoID
 | 
				
			|||||||
		return fmt.Errorf("list actions artifacts of repo %v: %w", repoID, err)
 | 
							return fmt.Errorf("list actions artifacts of repo %v: %w", repoID, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// In case is a organization.
 | 
						// In case owner is a organization, we have to change repo specific teams
 | 
				
			||||||
	org, err := user_model.GetUserByID(ctx, repo.OwnerID)
 | 
						// if ignoreOrgTeams is not true
 | 
				
			||||||
	if err != nil {
 | 
						var org *user_model.User
 | 
				
			||||||
		return err
 | 
						if len(ignoreOrgTeams) == 0 || !ignoreOrgTeams[0] {
 | 
				
			||||||
 | 
							if org, err = user_model.GetUserByID(ctx, repo.OwnerID); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Delete Deploy Keys
 | 
						// Delete Deploy Keys
 | 
				
			||||||
@@ -93,7 +96,7 @@ func DeleteRepositoryDirectly(ctx context.Context, doer *user_model.User, repoID
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if org.IsOrganization() {
 | 
						if org != nil && org.IsOrganization() {
 | 
				
			||||||
		teams, err := organization.FindOrgTeams(ctx, org.ID)
 | 
							teams, err := organization.FindOrgTeams(ctx, org.ID)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user