1
1
mirror of https://github.com/go-gitea/gitea synced 2025-07-13 14:07:20 +00:00

Rework create/fork/adopt/generate repository to make sure resources will be cleanup once failed (#31035)

Fix #28144 

To make the resources will be cleanup once failed. All repository
operations now follow a consistent pattern:

- 1. Create a database record for the repository with the status
being_migrated.
- 2. Register a deferred cleanup function to delete the repository and
its related data if the operation fails.
- 3.	Perform the actual Git and database operations step by step.
- 4. Upon successful completion, update the repository’s status to
ready.

The adopt operation is a special case — if it fails, the repository on
disk should not be deleted.
This commit is contained in:
Lunny Xiao
2025-04-07 22:12:54 -07:00
committed by GitHub
parent 90b509aafb
commit a100ac3306
14 changed files with 562 additions and 390 deletions

View File

@ -4,13 +4,16 @@
package repository
import (
"os"
"testing"
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
"github.com/stretchr/testify/assert"
)
@ -46,3 +49,43 @@ func TestForkRepository(t *testing.T) {
assert.Nil(t, fork2)
assert.True(t, repo_model.IsErrReachLimitOfRepo(err))
}
func TestForkRepositoryCleanup(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
// a successful fork
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
repo10 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10})
fork, err := ForkRepository(git.DefaultContext, user2, user2, ForkRepoOptions{
BaseRepo: repo10,
Name: "test",
})
assert.NoError(t, err)
assert.NotNil(t, fork)
exist, err := util.IsExist(repo_model.RepoPath(user2.Name, "test"))
assert.NoError(t, err)
assert.True(t, exist)
err = DeleteRepositoryDirectly(db.DefaultContext, user2, fork.ID)
assert.NoError(t, err)
// a failed creating because some mock data
// create the repository directory so that the creation will fail after database record created.
assert.NoError(t, os.MkdirAll(repo_model.RepoPath(user2.Name, "test"), os.ModePerm))
fork2, err := ForkRepository(db.DefaultContext, user2, user2, ForkRepoOptions{
BaseRepo: repo10,
Name: "test",
})
assert.Nil(t, fork2)
assert.Error(t, err)
// assert the cleanup is successful
unittest.AssertNotExistsBean(t, &repo_model.Repository{OwnerName: user2.Name, Name: "test"})
exist, err = util.IsExist(repo_model.RepoPath(user2.Name, "test"))
assert.NoError(t, err)
assert.False(t, exist)
}