2020-12-01 23:56:04 -05:00
// 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"
2021-09-19 07:49:59 -04:00
"code.gitea.io/gitea/models/db"
2020-12-01 23:56:04 -05:00
"code.gitea.io/gitea/models/migrations"
"code.gitea.io/gitea/modules/log"
2021-03-18 02:06:40 -04:00
"code.gitea.io/gitea/modules/setting"
2020-12-01 23:56:04 -05:00
)
func checkDBConsistency ( logger log . Logger , autofix bool ) error {
// make sure DB version is uptodate
2021-09-19 07:49:59 -04:00
if err := db . NewEngine ( context . Background ( ) , migrations . EnsureUpToDate ) ; err != nil {
2020-12-01 23:56:04 -05:00
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 {
2021-04-30 15:10:39 -04:00
logger . Critical ( "Error: %v whilst counting orphaned labels" , err )
2020-12-01 23:56:04 -05:00
return err
}
if count > 0 {
if autofix {
if err = models . DeleteOrphanedLabels ( ) ; err != nil {
2021-04-29 18:48:52 -04:00
logger . Critical ( "Error: %v whilst deleting orphaned labels" , err )
2020-12-01 23:56:04 -05:00
return err
}
logger . Info ( "%d labels without existing repository/organisation deleted" , count )
} else {
logger . Warn ( "%d labels without existing repository/organisation" , count )
}
}
2021-03-19 15:01:24 -04:00
// find IssueLabels without existing label
count , err = models . CountOrphanedIssueLabels ( )
if err != nil {
2021-04-30 15:10:39 -04:00
logger . Critical ( "Error: %v whilst counting orphaned issue_labels" , err )
2021-03-19 15:01:24 -04:00
return err
}
if count > 0 {
if autofix {
if err = models . DeleteOrphanedIssueLabels ( ) ; err != nil {
2021-04-29 18:48:52 -04:00
logger . Critical ( "Error: %v whilst deleting orphaned issue_labels" , err )
2021-03-19 15:01:24 -04:00
return err
}
logger . Info ( "%d issue_labels without existing label deleted" , count )
} else {
logger . Warn ( "%d issue_labels without existing label" , count )
}
}
2020-12-01 23:56:04 -05:00
// find issues without existing repository
count , err = models . CountOrphanedIssues ( )
if err != nil {
2021-04-30 15:10:39 -04:00
logger . Critical ( "Error: %v whilst counting orphaned issues" , err )
2020-12-01 23:56:04 -05:00
return err
}
if count > 0 {
if autofix {
if err = models . DeleteOrphanedIssues ( ) ; err != nil {
2021-04-29 18:48:52 -04:00
logger . Critical ( "Error: %v whilst deleting orphaned issues" , err )
2020-12-01 23:56:04 -05:00
return err
}
logger . Info ( "%d issues without existing repository deleted" , count )
} else {
logger . Warn ( "%d issues without existing repository" , count )
}
}
2021-09-14 15:41:40 -04:00
// find releases without existing repository
count , err = models . CountOrphanedObjects ( "release" , "repository" , "release.repo_id=repository.id" )
if err != nil {
logger . Critical ( "Error: %v whilst counting orphaned objects" , err )
return err
}
if count > 0 {
if autofix {
if err = models . DeleteOrphanedObjects ( "release" , "repository" , "release.repo_id=repository.id" ) ; err != nil {
logger . Critical ( "Error: %v whilst deleting orphaned objects" , err )
return err
}
logger . Info ( "%d releases without existing repository deleted" , count )
} else {
logger . Warn ( "%d releases without existing repository" , count )
}
}
2020-12-01 23:56:04 -05:00
// find pulls without existing issues
count , err = models . CountOrphanedObjects ( "pull_request" , "issue" , "pull_request.issue_id=issue.id" )
if err != nil {
2021-04-30 15:10:39 -04:00
logger . Critical ( "Error: %v whilst counting orphaned objects" , err )
2020-12-01 23:56:04 -05:00
return err
}
if count > 0 {
if autofix {
if err = models . DeleteOrphanedObjects ( "pull_request" , "issue" , "pull_request.issue_id=issue.id" ) ; err != nil {
2021-04-29 18:48:52 -04:00
logger . Critical ( "Error: %v whilst deleting orphaned objects" , err )
2020-12-01 23:56:04 -05:00
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 {
2021-04-30 15:10:39 -04:00
logger . Critical ( "Error: %v whilst counting orphaned objects" , err )
2020-12-01 23:56:04 -05:00
return err
}
if count > 0 {
if autofix {
if err = models . DeleteOrphanedObjects ( "tracked_time" , "issue" , "tracked_time.issue_id=issue.id" ) ; err != nil {
2021-04-29 18:48:52 -04:00
logger . Critical ( "Error: %v whilst deleting orphaned objects" , err )
2020-12-01 23:56:04 -05:00
return err
}
logger . Info ( "%d tracked times without existing issue deleted" , count )
} else {
logger . Warn ( "%d tracked times without existing issue" , count )
}
}
2021-09-14 15:41:40 -04:00
// find attachments without existing issues or releases
count , err = models . CountOrphanedAttachments ( )
if err != nil {
logger . Critical ( "Error: %v whilst counting orphaned objects" , err )
return err
}
if count > 0 {
if autofix {
if err = models . DeleteOrphanedAttachments ( ) ; err != nil {
logger . Critical ( "Error: %v whilst deleting orphaned objects" , err )
return err
}
logger . Info ( "%d attachments without existing issue or release deleted" , count )
} else {
logger . Warn ( "%d attachments without existing issue or release" , count )
}
}
2020-12-01 23:56:04 -05:00
// find null archived repositories
count , err = models . CountNullArchivedRepository ( )
if err != nil {
2021-04-30 15:10:39 -04:00
logger . Critical ( "Error: %v whilst counting null archived repositories" , err )
2020-12-01 23:56:04 -05:00
return err
}
if count > 0 {
if autofix {
updatedCount , err := models . FixNullArchivedRepository ( )
if err != nil {
2021-04-29 18:48:52 -04:00
logger . Critical ( "Error: %v whilst fixing null archived repositories" , err )
2020-12-01 23:56:04 -05:00
return err
}
logger . Info ( "%d repositories with null is_archived updated" , updatedCount )
} else {
logger . Warn ( "%d repositories with null is_archived" , count )
}
}
2021-02-09 21:50:44 -05:00
// find label comments with empty labels
count , err = models . CountCommentTypeLabelWithEmptyLabel ( )
if err != nil {
2021-04-30 15:10:39 -04:00
logger . Critical ( "Error: %v whilst counting label comments with empty labels" , err )
2021-02-09 21:50:44 -05:00
return err
}
if count > 0 {
if autofix {
updatedCount , err := models . FixCommentTypeLabelWithEmptyLabel ( )
if err != nil {
2021-04-29 18:48:52 -04:00
logger . Critical ( "Error: %v whilst removing label comments with empty labels" , err )
2021-02-09 21:50:44 -05:00
return err
}
logger . Info ( "%d label comments with empty labels removed" , updatedCount )
} else {
logger . Warn ( "%d label comments with empty labels" , count )
}
}
2021-03-19 09:25:14 -04:00
// find label comments with labels from outside the repository
count , err = models . CountCommentTypeLabelWithOutsideLabels ( )
if err != nil {
logger . Critical ( "Error: %v whilst counting label comments with outside labels" , err )
return err
}
if count > 0 {
if autofix {
updatedCount , err := models . FixCommentTypeLabelWithOutsideLabels ( )
if err != nil {
logger . Critical ( "Error: %v whilst removing label comments with outside labels" , err )
return err
}
log . Info ( "%d label comments with outside labels removed" , updatedCount )
} else {
log . Warn ( "%d label comments with outside labels" , count )
}
}
// find issue_label with labels from outside the repository
count , err = models . CountIssueLabelWithOutsideLabels ( )
if err != nil {
logger . Critical ( "Error: %v whilst counting issue_labels from outside the repository or organisation" , err )
return err
}
if count > 0 {
if autofix {
updatedCount , err := models . FixIssueLabelWithOutsideLabels ( )
if err != nil {
logger . Critical ( "Error: %v whilst removing issue_labels from outside the repository or organisation" , err )
return err
}
logger . Info ( "%d issue_labels from outside the repository or organisation removed" , updatedCount )
} else {
logger . Warn ( "%d issue_labels from outside the repository or organisation" , count )
}
}
2020-12-01 23:56:04 -05:00
// TODO: function to recalc all counters
2021-03-18 02:06:40 -04:00
if setting . Database . UsePostgreSQL {
2021-09-19 07:49:59 -04:00
count , err = db . CountBadSequences ( )
2021-03-18 02:06:40 -04:00
if err != nil {
2021-04-30 15:10:39 -04:00
logger . Critical ( "Error: %v whilst checking sequence values" , err )
return err
2021-03-18 02:06:40 -04:00
}
if count > 0 {
if autofix {
2021-09-19 07:49:59 -04:00
err := db . FixBadSequences ( )
2021-03-18 02:06:40 -04:00
if err != nil {
2021-04-29 18:48:52 -04:00
logger . Critical ( "Error: %v whilst attempting to fix sequences" , err )
2021-03-18 02:06:40 -04:00
return err
}
logger . Info ( "%d sequences updated" , count )
} else {
logger . Warn ( "%d sequences with incorrect values" , count )
}
}
}
2021-04-29 18:48:52 -04:00
// find protected branches without existing repository
count , err = models . CountOrphanedObjects ( "protected_branch" , "repository" , "protected_branch.repo_id=repository.id" )
if err != nil {
2021-04-30 15:10:39 -04:00
logger . Critical ( "Error: %v whilst counting orphaned objects" , err )
2021-04-29 18:48:52 -04:00
return err
}
if count > 0 {
if autofix {
if err = models . DeleteOrphanedObjects ( "protected_branch" , "repository" , "protected_branch.repo_id=repository.id" ) ; err != nil {
logger . Critical ( "Error: %v whilst deleting orphaned objects" , err )
return err
}
logger . Info ( "%d protected branches without existing repository deleted" , count )
} else {
logger . Warn ( "%d protected branches without existing repository" , count )
}
}
2021-04-30 15:10:39 -04:00
// find deleted branches without existing repository
count , err = models . CountOrphanedObjects ( "deleted_branch" , "repository" , "deleted_branch.repo_id=repository.id" )
if err != nil {
logger . Critical ( "Error: %v whilst counting orphaned objects" , err )
return err
}
if count > 0 {
if autofix {
if err = models . DeleteOrphanedObjects ( "deleted_branch" , "repository" , "deleted_branch.repo_id=repository.id" ) ; err != nil {
logger . Critical ( "Error: %v whilst deleting orphaned objects" , err )
return err
}
logger . Info ( "%d deleted branches without existing repository deleted" , count )
} else {
logger . Warn ( "%d deleted branches without existing repository" , count )
}
}
// find LFS locks without existing repository
count , err = models . CountOrphanedObjects ( "lfs_lock" , "repository" , "lfs_lock.repo_id=repository.id" )
if err != nil {
logger . Critical ( "Error: %v whilst counting orphaned objects" , err )
return err
}
if count > 0 {
if autofix {
if err = models . DeleteOrphanedObjects ( "lfs_lock" , "repository" , "lfs_lock.repo_id=repository.id" ) ; err != nil {
logger . Critical ( "Error: %v whilst deleting orphaned objects" , err )
return err
}
logger . Info ( "%d LFS locks without existing repository deleted" , count )
} else {
logger . Warn ( "%d LFS locks without existing repository" , count )
}
}
2020-12-01 23:56:04 -05:00
return nil
}
func init ( ) {
Register ( & Check {
Title : "Check consistency of database" ,
Name : "check-db-consistency" ,
IsDefault : false ,
Run : checkDBConsistency ,
Priority : 3 ,
} )
}