Skip to content

Commit aabcf2d

Browse files
authored
Add doctor dbconsistency fix to delete repos with no owner (#27290) (#27693)
Backport #27290
1 parent 6919a02 commit aabcf2d

File tree

2 files changed

+79
-6
lines changed

2 files changed

+79
-6
lines changed

modules/doctor/repository.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
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+
repo_service "code.gitea.io/gitea/services/repository"
13+
14+
"xorm.io/builder"
15+
)
16+
17+
func handleDeleteOrphanedRepos(ctx context.Context, logger log.Logger, autofix bool) error {
18+
test := &consistencyCheck{
19+
Name: "Repos with no existing owner",
20+
Counter: countOrphanedRepos,
21+
Fixer: deleteOrphanedRepos,
22+
FixedMessage: "Deleted all content related to orphaned repos",
23+
}
24+
return test.Run(ctx, logger, autofix)
25+
}
26+
27+
// countOrphanedRepos count repository where user of owner_id do not exist
28+
func countOrphanedRepos(ctx context.Context) (int64, error) {
29+
return db.CountOrphanedObjects(ctx, "repository", "user", "repository.owner_id=user.id")
30+
}
31+
32+
// deleteOrphanedRepos delete repository where user of owner_id do not exist
33+
func deleteOrphanedRepos(ctx context.Context) (int64, error) {
34+
batchSize := db.MaxBatchInsertSize("repository")
35+
e := db.GetEngine(ctx)
36+
var deleted int64
37+
adminUser := &user_model.User{IsAdmin: true}
38+
39+
for {
40+
var ids []int64
41+
if err := e.Table("`repository`").
42+
Join("LEFT", "`user`", "repository.owner_id=user.id").
43+
Where(builder.IsNull{"`user`.id"}).
44+
Select("`repository`.id").Limit(batchSize).Find(&ids); err != nil {
45+
return deleted, err
46+
}
47+
48+
// if we don't get ids we have deleted them all
49+
if len(ids) == 0 {
50+
return deleted, nil
51+
}
52+
53+
for _, id := range ids {
54+
if err := repo_service.DeleteRepositoryDirectly(ctx, adminUser, 0, id, true); err != nil {
55+
return deleted, err
56+
}
57+
deleted++
58+
}
59+
}
60+
}
61+
62+
func init() {
63+
Register(&Check{
64+
Title: "Deleted all content related to orphaned repos",
65+
Name: "delete-orphaned-repos",
66+
IsDefault: false,
67+
Run: handleDeleteOrphanedRepos,
68+
Priority: 4,
69+
})
70+
}

services/repository/delete.go

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import (
3333

3434
// DeleteRepository deletes a repository for a user or organization.
3535
// make sure if you call this func to close open sessions (sqlite will otherwise get a deadlock)
36-
func DeleteRepositoryDirectly(ctx context.Context, doer *user_model.User, uid, repoID int64) error {
36+
func DeleteRepositoryDirectly(ctx context.Context, doer *user_model.User, uid, repoID int64, ignoreOrgTeams ...bool) error {
3737
ctx, committer, err := db.TxContext(ctx)
3838
if err != nil {
3939
return err
@@ -53,10 +53,13 @@ func DeleteRepositoryDirectly(ctx context.Context, doer *user_model.User, uid, r
5353
return fmt.Errorf("list actions artifacts of repo %v: %w", repoID, err)
5454
}
5555

56-
// In case is a organization.
57-
org, err := user_model.GetUserByID(ctx, uid)
58-
if err != nil {
59-
return err
56+
// In case owner is a organization, we have to change repo specific teams
57+
// if ignoreOrgTeams is not true
58+
var org *user_model.User
59+
if len(ignoreOrgTeams) == 0 || !ignoreOrgTeams[0] {
60+
if org, err = user_model.GetUserByID(ctx, uid); err != nil {
61+
return err
62+
}
6063
}
6164

6265
repo := &repo_model.Repository{OwnerID: uid}
@@ -95,7 +98,7 @@ func DeleteRepositoryDirectly(ctx context.Context, doer *user_model.User, uid, r
9598
}
9699
}
97100

98-
if org.IsOrganization() {
101+
if org != nil && org.IsOrganization() {
99102
teams, err := organization.FindOrgTeams(ctx, org.ID)
100103
if err != nil {
101104
return err

0 commit comments

Comments
 (0)