summaryrefslogtreecommitdiffstats
path: root/modules/doctor/dbconsistency.go
blob: 942a45cb30d45f67e9001008b7a7b3336a8b0496 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// Copyright 2020 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package doctor

import (
	"context"

	"code.gitea.io/gitea/models"
	"code.gitea.io/gitea/models/migrations"
	"code.gitea.io/gitea/modules/log"
)

func checkDBConsistency(logger log.Logger, autofix bool) error {
	// make sure DB version is uptodate
	if err := models.NewEngine(context.Background(), migrations.EnsureUpToDate); err != nil {
		logger.Critical("Model version on the database does not match the current Gitea version. Model consistency will not be checked until the database is upgraded")
		return err
	}

	// find labels without existing repo or org
	count, err := models.CountOrphanedLabels()
	if err != nil {
		logger.Critical("Error: %v whilst counting orphaned labels")
		return err
	}

	if count > 0 {
		if autofix {
			if err = models.DeleteOrphanedLabels(); err != nil {
				logger.Critical("Error: %v whilst deleting orphaned labels")
				return err
			}
			logger.Info("%d labels without existing repository/organisation deleted", count)
		} else {
			logger.Warn("%d labels without existing repository/organisation", count)
		}
	}

	// find issues without existing repository
	count, err = models.CountOrphanedIssues()
	if err != nil {
		logger.Critical("Error: %v whilst counting orphaned issues")
		return err
	}
	if count > 0 {
		if autofix {
			if err = models.DeleteOrphanedIssues(); err != nil {
				logger.Critical("Error: %v whilst deleting orphaned issues")
				return err
			}
			logger.Info("%d issues without existing repository deleted", count)
		} else {
			logger.Warn("%d issues without existing repository", count)
		}
	}

	// find pulls without existing issues
	count, err = models.CountOrphanedObjects("pull_request", "issue", "pull_request.issue_id=issue.id")
	if err != nil {
		logger.Critical("Error: %v whilst counting orphaned objects")
		return err
	}
	if count > 0 {
		if autofix {
			if err = models.DeleteOrphanedObjects("pull_request", "issue", "pull_request.issue_id=issue.id"); err != nil {
				logger.Critical("Error: %v whilst deleting orphaned objects")
				return err
			}
			logger.Info("%d pull requests without existing issue deleted", count)
		} else {
			logger.Warn("%d pull requests without existing issue", count)
		}
	}

	// find tracked times without existing issues/pulls
	count, err = models.CountOrphanedObjects("tracked_time", "issue", "tracked_time.issue_id=issue.id")
	if err != nil {
		logger.Critical("Error: %v whilst counting orphaned objects")
		return err
	}
	if count > 0 {
		if autofix {
			if err = models.DeleteOrphanedObjects("tracked_time", "issue", "tracked_time.issue_id=issue.id"); err != nil {
				logger.Critical("Error: %v whilst deleting orphaned objects")
				return err
			}
			logger.Info("%d tracked times without existing issue deleted", count)
		} else {
			logger.Warn("%d tracked times without existing issue", count)
		}
	}

	// find null archived repositories
	count, err = models.CountNullArchivedRepository()
	if err != nil {
		logger.Critical("Error: %v whilst counting null archived repositories")
		return err
	}
	if count > 0 {
		if autofix {
			updatedCount, err := models.FixNullArchivedRepository()
			if err != nil {
				logger.Critical("Error: %v whilst fixing null archived repositories")
				return err
			}
			logger.Info("%d repositories with null is_archived updated", updatedCount)
		} else {
			logger.Warn("%d repositories with null is_archived", count)
		}
	}

	// find label comments with empty labels
	count, err = models.CountCommentTypeLabelWithEmptyLabel()
	if err != nil {
		logger.Critical("Error: %v whilst counting label comments with empty labels")
		return err
	}
	if count > 0 {
		if autofix {
			updatedCount, err := models.FixCommentTypeLabelWithEmptyLabel()
			if err != nil {
				logger.Critical("Error: %v whilst removing label comments with empty labels")
				return err
			}
			logger.Info("%d label comments with empty labels removed", updatedCount)
		} else {
			logger.Warn("%d label comments with empty labels", count)
		}
	}
	// TODO: function to recalc all counters

	return nil
}

func init() {
	Register(&Check{
		Title:     "Check consistency of database",
		Name:      "check-db-consistency",
		IsDefault: false,
		Run:       checkDBConsistency,
		Priority:  3,
	})
}