Skip to content

Commit e83f2cb

Browse files
authored
Add doctor dbconsistency fix to delete repos with no owner (#27290)
to address #27273 replace #24873
1 parent 3dc0c96 commit e83f2cb

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, 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, repoID int64) error {
36+
func DeleteRepositoryDirectly(ctx context.Context, doer *user_model.User, repoID int64, ignoreOrgTeams ...bool) error {
3737
ctx, committer, err := db.TxContext(ctx)
3838
if err != nil {
3939
return err
@@ -65,10 +65,13 @@ func DeleteRepositoryDirectly(ctx context.Context, doer *user_model.User, repoID
6565
return fmt.Errorf("list actions artifacts of repo %v: %w", repoID, err)
6666
}
6767

68-
// In case is a organization.
69-
org, err := user_model.GetUserByID(ctx, repo.OwnerID)
70-
if err != nil {
71-
return err
68+
// In case owner is a organization, we have to change repo specific teams
69+
// if ignoreOrgTeams is not true
70+
var org *user_model.User
71+
if len(ignoreOrgTeams) == 0 || !ignoreOrgTeams[0] {
72+
if org, err = user_model.GetUserByID(ctx, repo.OwnerID); err != nil {
73+
return err
74+
}
7275
}
7376

7477
// Delete Deploy Keys
@@ -93,7 +96,7 @@ func DeleteRepositoryDirectly(ctx context.Context, doer *user_model.User, repoID
9396
}
9497
}
9598

96-
if org.IsOrganization() {
99+
if org != nil && org.IsOrganization() {
97100
teams, err := organization.FindOrgTeams(ctx, org.ID)
98101
if err != nil {
99102
return err

0 commit comments

Comments
 (0)