mirror of
				https://codeberg.org/forgejo/forgejo.git
				synced 2025-10-30 22:11:07 +00:00 
			
		
		
		
	Add doctor dbconsistency fix to delete repos with no owner (#27290)
to address #27273 replace #24873
This commit is contained in:
		
					parent
					
						
							
								3dc0c962bf
							
						
					
				
			
			
				commit
				
					
						e83f2cbbac
					
				
			
		
					 2 changed files with 79 additions and 6 deletions
				
			
		
							
								
								
									
										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. | ||||
| // 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) | ||||
| 	if err != nil { | ||||
| 		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) | ||||
| 	} | ||||
| 
 | ||||
| 	// In case is a organization. | ||||
| 	org, err := user_model.GetUserByID(ctx, repo.OwnerID) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	// In case owner is a organization, we have to change repo specific teams | ||||
| 	// if ignoreOrgTeams is not true | ||||
| 	var org *user_model.User | ||||
| 	if len(ignoreOrgTeams) == 0 || !ignoreOrgTeams[0] { | ||||
| 		if org, err = user_model.GetUserByID(ctx, repo.OwnerID); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// 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) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue