mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 08:30:25 +08:00 
			
		
		
		
	[doctor] Add check/fix for bogus action rows (#19656)
Signed-off-by: Loïc Dachary <loic@dachary.org> Co-authored-by: Loïc Dachary <loic@dachary.org>
This commit is contained in:
		@@ -9,6 +9,7 @@ import (
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
	user_model "code.gitea.io/gitea/models/user"
 | 
			
		||||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/builder"
 | 
			
		||||
)
 | 
			
		||||
@@ -246,3 +247,23 @@ func FixIssueLabelWithOutsideLabels() (int64, error) {
 | 
			
		||||
 | 
			
		||||
	return res.RowsAffected()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CountActionCreatedUnixString count actions where created_unix is an empty string
 | 
			
		||||
func CountActionCreatedUnixString() (int64, error) {
 | 
			
		||||
	if setting.Database.UseSQLite3 {
 | 
			
		||||
		return db.GetEngine(db.DefaultContext).Where(`created_unix = ""`).Count(new(Action))
 | 
			
		||||
	}
 | 
			
		||||
	return 0, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FixActionCreatedUnixString set created_unix to zero if it is an empty string
 | 
			
		||||
func FixActionCreatedUnixString() (int64, error) {
 | 
			
		||||
	if setting.Database.UseSQLite3 {
 | 
			
		||||
		res, err := db.GetEngine(db.DefaultContext).Exec(`UPDATE action SET created_unix = 0 WHERE created_unix = ""`)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return 0, err
 | 
			
		||||
		}
 | 
			
		||||
		return res.RowsAffected()
 | 
			
		||||
	}
 | 
			
		||||
	return 0, nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,7 @@ import (
 | 
			
		||||
	issues_model "code.gitea.io/gitea/models/issues"
 | 
			
		||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
	"code.gitea.io/gitea/models/unittest"
 | 
			
		||||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
	"code.gitea.io/gitea/modules/timeutil"
 | 
			
		||||
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
@@ -103,3 +104,46 @@ func TestUpdateMilestoneCounters(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, issues_model.UpdateMilestoneCounters(db.DefaultContext, issue.MilestoneID))
 | 
			
		||||
	unittest.CheckConsistencyFor(t, &issues_model.Milestone{})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestConsistencyUpdateAction(t *testing.T) {
 | 
			
		||||
	if !setting.Database.UseSQLite3 {
 | 
			
		||||
		t.Skip("Test is only for SQLite database.")
 | 
			
		||||
	}
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	id := 8
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &Action{
 | 
			
		||||
		ID: int64(id),
 | 
			
		||||
	})
 | 
			
		||||
	_, err := db.GetEngine(db.DefaultContext).Exec(`UPDATE action SET created_unix = "" WHERE id = ?`, id)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	actions := make([]*Action, 0, 1)
 | 
			
		||||
	//
 | 
			
		||||
	// XORM returns an error when created_unix is a string
 | 
			
		||||
	//
 | 
			
		||||
	err = db.GetEngine(db.DefaultContext).Where("id = ?", id).Find(&actions)
 | 
			
		||||
	if assert.Error(t, err) {
 | 
			
		||||
		assert.Contains(t, err.Error(), "type string to a int64: invalid syntax")
 | 
			
		||||
	}
 | 
			
		||||
	//
 | 
			
		||||
	// Get rid of incorrectly set created_unix
 | 
			
		||||
	//
 | 
			
		||||
	count, err := CountActionCreatedUnixString()
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.EqualValues(t, 1, count)
 | 
			
		||||
	count, err = FixActionCreatedUnixString()
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.EqualValues(t, 1, count)
 | 
			
		||||
 | 
			
		||||
	count, err = CountActionCreatedUnixString()
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.EqualValues(t, 0, count)
 | 
			
		||||
	count, err = FixActionCreatedUnixString()
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.EqualValues(t, 0, count)
 | 
			
		||||
 | 
			
		||||
	//
 | 
			
		||||
	// XORM must be happy now
 | 
			
		||||
	//
 | 
			
		||||
	assert.NoError(t, db.GetEngine(db.DefaultContext).Where("id = ?", id).Find(&actions))
 | 
			
		||||
	unittest.CheckConsistencyFor(t, &Action{})
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -142,6 +142,12 @@ func checkDBConsistency(ctx context.Context, logger log.Logger, autofix bool) er
 | 
			
		||||
			Fixer:        models.FixIssueLabelWithOutsideLabels,
 | 
			
		||||
			FixedMessage: "Removed",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			Name:         "Action with created_unix set as an empty string",
 | 
			
		||||
			Counter:      models.CountActionCreatedUnixString,
 | 
			
		||||
			Fixer:        models.FixActionCreatedUnixString,
 | 
			
		||||
			FixedMessage: "Set to zero",
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// TODO: function to recalc all counters
 | 
			
		||||
@@ -177,6 +183,9 @@ func checkDBConsistency(ctx context.Context, logger log.Logger, autofix bool) er
 | 
			
		||||
		// find access without repository
 | 
			
		||||
		genericOrphanCheck("Access entries without existing repository",
 | 
			
		||||
			"access", "repository", "access.repo_id=repository.id"),
 | 
			
		||||
		// find action without repository
 | 
			
		||||
		genericOrphanCheck("Action entries without existing repository",
 | 
			
		||||
			"action", "repository", "action.repo_id=repository.id"),
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	for _, c := range consistencyChecks {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user