Skip to content

Commit 0c8c90d

Browse files
committed
Add outside label consistency check into doctor
This PR adds another consistency check into doctor in order to detect labels that have been added from outside of repositories and organisations Fix #14908 Signed-off-by: Andrew Thornton <[email protected]>
1 parent cd215d0 commit 0c8c90d

File tree

4 files changed

+172
-0
lines changed

4 files changed

+172
-0
lines changed

models/consistency.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,3 +315,61 @@ func CountCommentTypeLabelWithEmptyLabel() (int64, error) {
315315
func FixCommentTypeLabelWithEmptyLabel() (int64, error) {
316316
return x.Where(builder.Eq{"type": CommentTypeLabel, "label_id": 0}).Delete(new(Comment))
317317
}
318+
319+
// CountCommentTypeLabelWithOutsideLabels count label comments with outside label
320+
func CountCommentTypeLabelWithOutsideLabels() (int64, error) {
321+
return x.Where("comment.type = ? AND (issue.repo_id != label.repo_id OR (label.repo_id = 0 AND repository.owner_id != label.org_id))", CommentTypeLabel).
322+
Table("comment").
323+
Join("inner", "label", "label.id = comment.label_id").
324+
Join("inner", "issue", "issue.id = comment.issue_id ").
325+
Join("inner", "repository", "issue.repo_id = repository.id").
326+
Count(new(Comment))
327+
}
328+
329+
// FixCommentTypeLabelWithOutsideLabels count label comments with outside label
330+
func FixCommentTypeLabelWithOutsideLabels() (int64, error) {
331+
res, err := x.Exec(`DELETE FROM comment WHERE comment.id IN (
332+
SELECT il_too.id FROM (
333+
SELECT com.id
334+
FROM comment AS com
335+
INNER JOIN label ON com.label_id = label.id
336+
INNER JOIN issue on issue.id = com.issue_id
337+
WHERE
338+
com.type = ? AND (issue.repo_id != label.repo_id OR (label.repo_id = 0 AND label.org_id != repo.owner_id))
339+
) AS il_too)`, CommentTypeLabel)
340+
if err != nil {
341+
return 0, err
342+
}
343+
344+
return res.RowsAffected()
345+
}
346+
347+
// CountIssueLabelWithOutsideLabels count label comments with outside label
348+
func CountIssueLabelWithOutsideLabels() (int64, error) {
349+
return x.Where(builder.Expr("issue.repo_id != label.repo_id OR (label.repo_id = 0 AND repository.owner_id != label.org_id)")).
350+
Table("issue_label").
351+
Join("inner", "label", "issue_label.id = label.id ").
352+
Join("inner", "issue", "issue.id = issue_label.issue_id ").
353+
Join("inner", "repository", "issue.repo_id = repository.id").
354+
Count(new(IssueLabel))
355+
}
356+
357+
// FixIssueLabelWithOutsideLabels fix label comments with outside label
358+
func FixIssueLabelWithOutsideLabels() (int64, error) {
359+
res, err := x.Exec(`DELETE FROM issue_label WHERE issue_label.id IN (
360+
SELECT il_too.id FROM (
361+
SELECT il_too_too.id
362+
FROM issue_label AS il_too_too
363+
INNER JOIN label ON il_too_too.id = label.id
364+
INNER JOIN issue on issue.id = il_too_too.issue_id
365+
INNER JOIN repository on repository.id = issue.repo_id
366+
WHERE
367+
issue.repo_id != label.repo_id OR (label.repo_id = 0 AND label.org_id != repository.owner_id)
368+
) AS il_too )`)
369+
370+
if err != nil {
371+
return 0, err
372+
}
373+
374+
return res.RowsAffected()
375+
}

models/migrations/migrations.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,8 @@ var migrations = []Migration{
296296
NewMigration("Add time_id column to Comment", addTimeIDCommentColumn),
297297
// v174 -> v175
298298
NewMigration("create repo transfer table", addRepoTransfer),
299+
// v175 -> v176
300+
NewMigration("remove invalid labels from comments", removeInvalidLabels),
299301
}
300302

301303
// GetCurrentDBVersion returns the current db version

models/migrations/v175.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// Copyright 2021 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package migrations
6+
7+
import (
8+
"xorm.io/xorm"
9+
)
10+
11+
func removeInvalidLabels(x *xorm.Engine) error {
12+
type Comment struct {
13+
ID int64 `xorm:"pk autoincr"`
14+
Type int `xorm:"INDEX"`
15+
IssueID int64 `xorm:"INDEX"`
16+
LabelID int64
17+
}
18+
19+
type Issue struct {
20+
ID int64 `xorm:"pk autoincr"`
21+
RepoID int64 `xorm:"INDEX UNIQUE(repo_index)"`
22+
Index int64 `xorm:"UNIQUE(repo_index)"` // Index in one repository.
23+
}
24+
25+
type Repository struct {
26+
ID int64 `xorm:"pk autoincr"`
27+
OwnerID int64 `xorm:"UNIQUE(s) index"`
28+
LowerName string `xorm:"UNIQUE(s) INDEX NOT NULL"`
29+
}
30+
31+
type Label struct {
32+
ID int64 `xorm:"pk autoincr"`
33+
RepoID int64 `xorm:"INDEX"`
34+
OrgID int64 `xorm:"INDEX"`
35+
}
36+
37+
type IssueLabel struct {
38+
ID int64 `xorm:"pk autoincr"`
39+
IssueID int64 `xorm:"UNIQUE(s)"`
40+
LabelID int64 `xorm:"UNIQUE(s)"`
41+
}
42+
43+
if err := x.Sync2(new(Comment), new(Issue), new(Repository), new(Label), new(IssueLabel)); err != nil {
44+
return err
45+
}
46+
47+
if _, err := x.Exec(`DELETE FROM comment WHERE comment.id IN (
48+
SELECT il_too.id FROM (
49+
SELECT com.id
50+
FROM comment AS com
51+
INNER JOIN label ON com.label_id = label.id
52+
INNER JOIN issue on issue.id = com.issue_id
53+
WHERE
54+
com.type = ? AND (issue.repo_id != label.repo_id OR (label.repo_id = 0 AND label.org_id != repo.owner_id))
55+
) AS il_too)`, 7); err != nil {
56+
return err
57+
}
58+
59+
if _, err := x.Exec(`DELETE FROM issue_label WHERE issue_label.id IN (
60+
SELECT il_too.id FROM (
61+
SELECT il_too_too.id
62+
FROM issue_label AS il_too_too
63+
INNER JOIN label ON il_too_too.id = label.id
64+
INNER JOIN issue on issue.id = il_too_too.issue_id
65+
INNER JOIN repository on repository.id = issue.repo_id
66+
WHERE
67+
issue.repo_id != label.repo_id OR (label.repo_id = 0 AND label.org_id != repository.owner_id)
68+
) AS il_too )`); err != nil {
69+
return err
70+
}
71+
72+
return nil
73+
}

modules/doctor/dbconsistency.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,45 @@ func checkDBConsistency(logger log.Logger, autofix bool) error {
129129
logger.Warn("%d label comments with empty labels", count)
130130
}
131131
}
132+
133+
// find label comments with labels from outside the repository
134+
count, err = models.CountCommentTypeLabelWithOutsideLabels()
135+
if err != nil {
136+
logger.Critical("Error: %v whilst counting label comments with outside labels", err)
137+
return err
138+
}
139+
if count > 0 {
140+
if autofix {
141+
updatedCount, err := models.FixCommentTypeLabelWithOutsideLabels()
142+
if err != nil {
143+
logger.Critical("Error: %v whilst removing label comments with outside labels", err)
144+
return err
145+
}
146+
log.Info("%d label comments with outside labels removed", updatedCount)
147+
} else {
148+
log.Warn("%d label comments with outside labels", count)
149+
}
150+
}
151+
152+
// find issue_label with labels from outside the repository
153+
count, err = models.CountIssueLabelWithOutsideLabels()
154+
if err != nil {
155+
logger.Critical("Error: %v whilst counting issue_labels from outside the repository or organisation", err)
156+
return err
157+
}
158+
if count > 0 {
159+
if autofix {
160+
updatedCount, err := models.FixIssueLabelWithOutsideLabels()
161+
if err != nil {
162+
logger.Critical("Error: %v whilst removing issue_labels from outside the repository or organisation", err)
163+
return err
164+
}
165+
logger.Info("%d issue_labels from outside the repository or organisation removed", updatedCount)
166+
} else {
167+
logger.Warn("%d issue_labels from outside the repository or organisation", count)
168+
}
169+
}
170+
132171
// TODO: function to recalc all counters
133172

134173
return nil

0 commit comments

Comments
 (0)