Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 25 commits into from
Apr 8, 2025
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
2c02c2e
Cleanup resources when create/adopt/generate repository failed
lunny May 21, 2024
d66b905
Add transaction for CreateRepoByExample
lunny May 27, 2024
0bd9aa0
Merge branch 'main' into lunny/cleanup_failure_creation_of_repo
lunny Sep 23, 2024
f0917c4
Merge branch 'main' into lunny/cleanup_failure_creation_of_repo
lunny Mar 14, 2025
0a9a6c7
Merge branch 'main' into lunny/cleanup_failure_creation_of_repo
lunny Mar 26, 2025
60c85e7
Some improvements
lunny Mar 26, 2025
ec58717
Fix bug
lunny Mar 26, 2025
1d13cc3
Add tests
lunny Mar 27, 2025
96069bf
Merge branch 'main' into lunny/cleanup_failure_creation_of_repo
lunny Mar 27, 2025
eb8884c
Fix creating repository
lunny Mar 27, 2025
f6b6850
Merge branch 'main' into lunny/cleanup_failure_creation_of_repo
lunny Mar 27, 2025
dfc1d46
Merge branch 'main' into lunny/cleanup_failure_creation_of_repo
lunny Mar 28, 2025
a494a69
merge some functions
lunny Mar 30, 2025
34c8445
Merge branch 'main' into lunny/cleanup_failure_creation_of_repo
lunny Mar 30, 2025
9b0d0dd
Merge branch 'lunny/cleanup_failure_creation_of_repo' of github.com:l…
lunny Mar 30, 2025
0a54603
Fix bug
lunny Mar 30, 2025
2322172
some improvements
lunny Mar 30, 2025
0142df4
Refactor to make test easier
lunny Apr 8, 2025
b01bab6
Merge branch 'main' into lunny/cleanup_failure_creation_of_repo
lunny Apr 8, 2025
b61f417
Remove duplicated checks
lunny Apr 8, 2025
8d85006
Fix test
lunny Apr 8, 2025
5feb0dd
Update comments
lunny Apr 8, 2025
5a041cc
update test
lunny Apr 8, 2025
2053bc2
Merge branch 'main' into lunny/cleanup_failure_creation_of_repo
lunny Apr 8, 2025
131b458
Merge branch 'main' into lunny/cleanup_failure_creation_of_repo
lunny Apr 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 36 additions & 16 deletions services/repository/adopt.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"code.gitea.io/gitea/models/db"
git_model "code.gitea.io/gitea/models/git"
repo_model "code.gitea.io/gitea/models/repo"
system_model "code.gitea.io/gitea/models/system"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/container"
"code.gitea.io/gitea/modules/git"
Expand Down Expand Up @@ -48,28 +49,31 @@ func AdoptRepository(ctx context.Context, doer, u *user_model.User, opts CreateR
IsPrivate: opts.IsPrivate,
IsFsckEnabled: !opts.IsMirror,
CloseIssuesViaCommitInAnyBranch: setting.Repository.DefaultCloseIssuesViaCommitsInAnyBranch,
Status: opts.Status,
Status: repo_model.RepositoryBeingMigrated,
IsEmpty: !opts.AutoInit,
}

if err := db.WithTx(ctx, func(ctx context.Context) error {
repoPath := repo_model.RepoPath(u.Name, repo.Name)
isExist, err := util.IsExist(repoPath)
if err != nil {
log.Error("Unable to check if %s exists. Error: %v", repoPath, err)
return err
}
if !isExist {
return repo_model.ErrRepoNotExist{
OwnerName: u.Name,
Name: repo.Name,
}
repoPath := repo_model.RepoPath(u.Name, repo.Name)
isExist, err := util.IsExist(repoPath)
if err != nil {
log.Error("Unable to check if %s exists. Error: %v", repoPath, err)
return nil, err
}
if !isExist {
return nil, repo_model.ErrRepoNotExist{
OwnerName: u.Name,
Name: repo.Name,
}
}

if err := repo_module.CreateRepositoryByExample(ctx, doer, u, repo, true, false); err != nil {
return err
}
// create the repository database operations first
if err := db.WithTx(ctx, func(ctx context.Context) error {
return repo_module.CreateRepositoryByExample(ctx, doer, u, repo, true, false)
}); err != nil {
return nil, err
}

if err := db.WithTx(ctx, func(ctx context.Context) error {
// Re-fetch the repository from database before updating it (else it would
// override changes that were done earlier with sql)
if repo, err = repo_model.GetRepositoryByID(ctx, repo.ID); err != nil {
Expand Down Expand Up @@ -97,8 +101,24 @@ func AdoptRepository(ctx context.Context, doer, u *user_model.User, opts CreateR
log.Error("CreateRepository(git update-server-info) in %v: Stdout: %s\nError: %v", repo, stdout, err)
return fmt.Errorf("CreateRepository(git update-server-info): %w", err)
}

// update repository status
repo.Status = repo_model.RepositoryReady
if err = repo_model.UpdateRepositoryCols(ctx, repo, "status"); err != nil {
return fmt.Errorf("UpdateRepositoryCols: %w", err)
}

return nil
}); err != nil {
if repo != nil {
if errDelete := DeleteRepositoryDirectly(ctx, doer, repo.ID); errDelete != nil {
log.Error("Rollback deleteRepository: %v", errDelete)
// add system notice
if err := system_model.CreateRepositoryNotice("DeleteRepositoryDirectly failed when adopt repository: %v", errDelete); err != nil {
log.Error("CreateRepositoryNotice: %v", err)
}
}
}
return nil, err
}

Expand Down
31 changes: 21 additions & 10 deletions services/repository/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (

"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
system_model "code.gitea.io/gitea/models/system"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitrepo"
Expand Down Expand Up @@ -240,13 +241,15 @@ func CreateRepositoryDirectly(ctx context.Context, doer, u *user_model.User, opt
ObjectFormatName: opts.ObjectFormatName,
}

var rollbackRepo *repo_model.Repository
needsUpdateStatus := opts.Status != repo_model.RepositoryReady

if err := db.WithTx(ctx, func(ctx context.Context) error {
if err := repo_module.CreateRepositoryByExample(ctx, doer, u, repo, false, false); err != nil {
return err
}
return repo_module.CreateRepositoryByExample(ctx, doer, u, repo, false, false)
}); err != nil {
return nil, err
}

if err := db.WithTx(ctx, func(ctx context.Context) error {
// No need for init mirror.
if opts.IsMirror {
return nil
Expand Down Expand Up @@ -285,8 +288,6 @@ func CreateRepositoryDirectly(ctx context.Context, doer, u *user_model.User, opt
// Initialize Issue Labels if selected
if len(opts.IssueLabels) > 0 {
if err = repo_module.InitializeLabels(ctx, repo.ID, opts.IssueLabels, false); err != nil {
rollbackRepo = repo
rollbackRepo.OwnerID = u.ID
return fmt.Errorf("InitializeLabels: %w", err)
}
}
Expand All @@ -299,15 +300,25 @@ func CreateRepositoryDirectly(ctx context.Context, doer, u *user_model.User, opt
SetDescription(fmt.Sprintf("CreateRepository(git update-server-info): %s", repoPath)).
RunStdString(&git.RunOpts{Dir: repoPath}); err != nil {
log.Error("CreateRepository(git update-server-info) in %v: Stdout: %s\nError: %v", repo, stdout, err)
rollbackRepo = repo
rollbackRepo.OwnerID = u.ID
return fmt.Errorf("CreateRepository(git update-server-info): %w", err)
}

if needsUpdateStatus {
repo.Status = repo_model.RepositoryReady
if err = repo_model.UpdateRepositoryCols(ctx, repo, "status"); err != nil {
return fmt.Errorf("UpdateRepositoryCols: %w", err)
}
}

return nil
}); err != nil {
if rollbackRepo != nil {
if errDelete := DeleteRepositoryDirectly(ctx, doer, rollbackRepo.ID); errDelete != nil {
if repo != nil {
if errDelete := DeleteRepositoryDirectly(ctx, doer, repo.ID); errDelete != nil {
log.Error("Rollback deleteRepository: %v", errDelete)
// add system notice
if err := system_model.CreateRepositoryNotice("DeleteRepositoryDirectly failed when create repository: %v", errDelete); err != nil {
log.Error("CreateRepositoryNotice: %v", err)
}
}
}

Expand Down
19 changes: 18 additions & 1 deletion services/repository/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ import (
"strings"
"time"

"code.gitea.io/gitea/models/db"
git_model "code.gitea.io/gitea/models/git"
repo_model "code.gitea.io/gitea/models/repo"
system_model "code.gitea.io/gitea/models/system"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitrepo"
Expand Down Expand Up @@ -341,14 +343,29 @@ func generateRepository(ctx context.Context, doer, owner *user_model.User, templ
TemplateID: templateRepo.ID,
TrustModel: templateRepo.TrustModel,
ObjectFormatName: templateRepo.ObjectFormatName,
Status: repo_model.RepositoryBeingMigrated,
}

if err = repo_module.CreateRepositoryByExample(ctx, doer, owner, generateRepo, false, false); err != nil {
if err := db.WithTx(ctx, func(ctx context.Context) error {
return repo_module.CreateRepositoryByExample(ctx, doer, owner, generateRepo, false, false)
}); err != nil {
return nil, err
}

repoPath := generateRepo.RepoPath()
isExist, err := util.IsExist(repoPath)
defer func() {
if err != nil {
if errDelete := DeleteRepositoryDirectly(ctx, doer, generateRepo.ID); errDelete != nil {
log.Error("Rollback deleteRepository: %v", errDelete)
// add system notice
if err := system_model.CreateRepositoryNotice("DeleteRepositoryDirectly failed when generate repository: %v", errDelete); err != nil {
log.Error("CreateRepositoryNotice: %v", err)
}
}
}
}()

if err != nil {
log.Error("Unable to check if %s exists. Error: %v", repoPath, err)
return nil, err
Expand Down
29 changes: 23 additions & 6 deletions services/repository/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@ package repository

import (
"context"
"fmt"

"code.gitea.io/gitea/models/db"
git_model "code.gitea.io/gitea/models/git"
issues_model "code.gitea.io/gitea/models/issues"
repo_model "code.gitea.io/gitea/models/repo"
system_model "code.gitea.io/gitea/models/system"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
notify_service "code.gitea.io/gitea/services/notify"
)

Expand Down Expand Up @@ -69,13 +72,12 @@ func GenerateRepository(ctx context.Context, doer, owner *user_model.User, templ
}
}

var generateRepo *repo_model.Repository
if err = db.WithTx(ctx, func(ctx context.Context) error {
generateRepo, err = generateRepository(ctx, doer, owner, templateRepo, opts)
if err != nil {
return err
}
generateRepo, err := generateRepository(ctx, doer, owner, templateRepo, opts)
if err != nil {
return nil, err
}

if err = db.WithTx(ctx, func(ctx context.Context) error {
// Git Content
if opts.GitContent && !templateRepo.IsEmpty {
if err = GenerateGitContent(ctx, templateRepo, generateRepo); err != nil {
Expand Down Expand Up @@ -124,8 +126,23 @@ func GenerateRepository(ctx context.Context, doer, owner *user_model.User, templ
}
}

// update repository status to be ready
generateRepo.Status = repo_model.RepositoryReady
if err = repo_model.UpdateRepositoryCols(ctx, generateRepo, "status"); err != nil {
return fmt.Errorf("UpdateRepositoryCols: %w", err)
}

return nil
}); err != nil {
if generateRepo != nil {
if errDelete := DeleteRepositoryDirectly(ctx, doer, generateRepo.ID); errDelete != nil {
log.Error("Rollback deleteRepository: %v", errDelete)
// add system notice
if err := system_model.CreateRepositoryNotice("DeleteRepositoryDirectly failed when generate repository: %v", errDelete); err != nil {
log.Error("CreateRepositoryNotice: %v", err)
}
}
}
return nil, err
}

Expand Down
Loading