aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--models/actions/run.go115
-rw-r--r--models/actions/schedule.go89
-rw-r--r--models/actions/task.go116
-rw-r--r--models/actions/tasks_version.go44
-rw-r--r--models/activities/notification_list.go14
-rw-r--r--models/asymkey/gpg_key.go13
-rw-r--r--models/asymkey/gpg_key_verify.go111
-rw-r--r--models/asymkey/ssh_key.go99
-rw-r--r--models/asymkey/ssh_key_deploy.go56
-rw-r--r--models/asymkey/ssh_key_verify.go58
-rw-r--r--models/auth/oauth2.go76
-rw-r--r--models/auth/session.go84
-rw-r--r--models/git/commit_status.go46
-rw-r--r--models/git/lfs.go11
-rw-r--r--models/git/lfs_lock.go76
-rw-r--r--models/issues/comment.go211
-rw-r--r--models/issues/dependency.go123
-rw-r--r--models/issues/issue.go18
-rw-r--r--models/issues/issue_index.go22
-rw-r--r--models/issues/issue_label.go206
-rw-r--r--models/issues/issue_lock.go33
-rw-r--r--models/issues/issue_update.go247
-rw-r--r--models/issues/label.go71
-rw-r--r--models/issues/milestone.go176
-rw-r--r--models/issues/pull.go98
-rw-r--r--models/issues/reaction.go18
-rw-r--r--models/issues/review.go572
-rw-r--r--models/issues/tracked_time.go146
-rw-r--r--models/organization/org.go158
-rw-r--r--models/organization/team_unit.go23
-rw-r--r--models/project/project.go42
-rw-r--r--models/repo.go19
-rw-r--r--models/repo/language_stats.go147
-rw-r--r--models/repo/release.go34
-rw-r--r--models/repo/star.go77
-rw-r--r--models/repo/topic.go150
-rw-r--r--models/repo/update.go7
-rw-r--r--models/repo/upload.go10
-rw-r--r--models/user/email_address.go55
-rw-r--r--models/user/follow.go60
-rw-r--r--models/webhook/webhook.go25
-rw-r--r--modules/structs/issue.go3
-rw-r--r--modules/structs/repo.go29
-rw-r--r--options/locale/locale_en-US.ini342
-rw-r--r--options/locale/locale_zh-CN.ini19
-rw-r--r--poetry.toml3
-rw-r--r--routers/api/v1/repo/action.go34
-rw-r--r--routers/api/v1/repo/actions_run.go2
-rw-r--r--routers/api/v1/repo/pull.go2
-rw-r--r--routers/api/v1/repo/repo.go2
-rw-r--r--services/asymkey/deploy_key.go31
-rw-r--r--services/asymkey/ssh_key.go13
-rw-r--r--services/asymkey/ssh_key_principals.go42
-rw-r--r--services/issue/label.go38
-rw-r--r--services/issue/milestone.go15
-rw-r--r--services/issue/status.go30
-rw-r--r--services/org/team.go243
-rw-r--r--services/packages/cleanup/cleanup.go52
-rw-r--r--services/packages/packages.go19
-rw-r--r--services/pull/merge.go68
-rw-r--r--services/repository/avatar.go72
-rw-r--r--services/repository/collaboration.go50
-rw-r--r--services/repository/repo_team.go28
-rw-r--r--services/repository/setting.go52
-rw-r--r--services/user/avatar.go32
-rw-r--r--templates/swagger/ui.tmpl1
-rw-r--r--templates/swagger/v1_json.tmpl50
-rw-r--r--tests/integration/editor_test.go2
68 files changed, 2203 insertions, 2827 deletions
diff --git a/models/actions/run.go b/models/actions/run.go
index f0ab61b200..f5ccba06c2 100644
--- a/models/actions/run.go
+++ b/models/actions/run.go
@@ -282,77 +282,72 @@ func CancelPreviousJobs(ctx context.Context, repoID int64, ref, workflowID strin
// InsertRun inserts a run
// The title will be cut off at 255 characters if it's longer than 255 characters.
func InsertRun(ctx context.Context, run *ActionRun, jobs []*jobparser.SingleWorkflow) error {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- index, err := db.GetNextResourceIndex(ctx, "action_run_index", run.RepoID)
- if err != nil {
- return err
- }
- run.Index = index
- run.Title = util.EllipsisDisplayString(run.Title, 255)
-
- if err := db.Insert(ctx, run); err != nil {
- return err
- }
-
- if run.Repo == nil {
- repo, err := repo_model.GetRepositoryByID(ctx, run.RepoID)
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ index, err := db.GetNextResourceIndex(ctx, "action_run_index", run.RepoID)
if err != nil {
return err
}
- run.Repo = repo
- }
+ run.Index = index
+ run.Title = util.EllipsisDisplayString(run.Title, 255)
- if err := updateRepoRunsNumbers(ctx, run.Repo); err != nil {
- return err
- }
-
- runJobs := make([]*ActionRunJob, 0, len(jobs))
- var hasWaiting bool
- for _, v := range jobs {
- id, job := v.Job()
- needs := job.Needs()
- if err := v.SetJob(id, job.EraseNeeds()); err != nil {
+ if err := db.Insert(ctx, run); err != nil {
return err
}
- payload, _ := v.Marshal()
- status := StatusWaiting
- if len(needs) > 0 || run.NeedApproval {
- status = StatusBlocked
- } else {
- hasWaiting = true
+
+ if run.Repo == nil {
+ repo, err := repo_model.GetRepositoryByID(ctx, run.RepoID)
+ if err != nil {
+ return err
+ }
+ run.Repo = repo
}
- job.Name = util.EllipsisDisplayString(job.Name, 255)
- runJobs = append(runJobs, &ActionRunJob{
- RunID: run.ID,
- RepoID: run.RepoID,
- OwnerID: run.OwnerID,
- CommitSHA: run.CommitSHA,
- IsForkPullRequest: run.IsForkPullRequest,
- Name: job.Name,
- WorkflowPayload: payload,
- JobID: id,
- Needs: needs,
- RunsOn: job.RunsOn(),
- Status: status,
- })
- }
- if err := db.Insert(ctx, runJobs); err != nil {
- return err
- }
- // if there is a job in the waiting status, increase tasks version.
- if hasWaiting {
- if err := IncreaseTaskVersion(ctx, run.OwnerID, run.RepoID); err != nil {
+ if err := updateRepoRunsNumbers(ctx, run.Repo); err != nil {
return err
}
- }
- return committer.Commit()
+ runJobs := make([]*ActionRunJob, 0, len(jobs))
+ var hasWaiting bool
+ for _, v := range jobs {
+ id, job := v.Job()
+ needs := job.Needs()
+ if err := v.SetJob(id, job.EraseNeeds()); err != nil {
+ return err
+ }
+ payload, _ := v.Marshal()
+ status := StatusWaiting
+ if len(needs) > 0 || run.NeedApproval {
+ status = StatusBlocked
+ } else {
+ hasWaiting = true
+ }
+ job.Name = util.EllipsisDisplayString(job.Name, 255)
+ runJobs = append(runJobs, &ActionRunJob{
+ RunID: run.ID,
+ RepoID: run.RepoID,
+ OwnerID: run.OwnerID,
+ CommitSHA: run.CommitSHA,
+ IsForkPullRequest: run.IsForkPullRequest,
+ Name: job.Name,
+ WorkflowPayload: payload,
+ JobID: id,
+ Needs: needs,
+ RunsOn: job.RunsOn(),
+ Status: status,
+ })
+ }
+ if err := db.Insert(ctx, runJobs); err != nil {
+ return err
+ }
+
+ // if there is a job in the waiting status, increase tasks version.
+ if hasWaiting {
+ if err := IncreaseTaskVersion(ctx, run.OwnerID, run.RepoID); err != nil {
+ return err
+ }
+ }
+ return nil
+ })
}
func GetRunByRepoAndID(ctx context.Context, repoID, runID int64) (*ActionRun, error) {
diff --git a/models/actions/schedule.go b/models/actions/schedule.go
index 2edf483fe0..ffde5092e0 100644
--- a/models/actions/schedule.go
+++ b/models/actions/schedule.go
@@ -56,65 +56,54 @@ func CreateScheduleTask(ctx context.Context, rows []*ActionSchedule) error {
return nil
}
- // Begin transaction
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- // Loop through each schedule row
- for _, row := range rows {
- row.Title = util.EllipsisDisplayString(row.Title, 255)
- // Create new schedule row
- if err = db.Insert(ctx, row); err != nil {
- return err
- }
-
- // Loop through each schedule spec and create a new spec row
- now := time.Now()
-
- for _, spec := range row.Specs {
- specRow := &ActionScheduleSpec{
- RepoID: row.RepoID,
- ScheduleID: row.ID,
- Spec: spec,
- }
- // Parse the spec and check for errors
- schedule, err := specRow.Parse()
- if err != nil {
- continue // skip to the next spec if there's an error
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ // Loop through each schedule row
+ for _, row := range rows {
+ row.Title = util.EllipsisDisplayString(row.Title, 255)
+ // Create new schedule row
+ if err := db.Insert(ctx, row); err != nil {
+ return err
}
- specRow.Next = timeutil.TimeStamp(schedule.Next(now).Unix())
-
- // Insert the new schedule spec row
- if err = db.Insert(ctx, specRow); err != nil {
- return err
+ // Loop through each schedule spec and create a new spec row
+ now := time.Now()
+
+ for _, spec := range row.Specs {
+ specRow := &ActionScheduleSpec{
+ RepoID: row.RepoID,
+ ScheduleID: row.ID,
+ Spec: spec,
+ }
+ // Parse the spec and check for errors
+ schedule, err := specRow.Parse()
+ if err != nil {
+ continue // skip to the next spec if there's an error
+ }
+
+ specRow.Next = timeutil.TimeStamp(schedule.Next(now).Unix())
+
+ // Insert the new schedule spec row
+ if err = db.Insert(ctx, specRow); err != nil {
+ return err
+ }
}
}
- }
-
- // Commit transaction
- return committer.Commit()
+ return nil
+ })
}
func DeleteScheduleTaskByRepo(ctx context.Context, id int64) error {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- if _, err := db.GetEngine(ctx).Delete(&ActionSchedule{RepoID: id}); err != nil {
- return err
- }
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ if _, err := db.GetEngine(ctx).Delete(&ActionSchedule{RepoID: id}); err != nil {
+ return err
+ }
- if _, err := db.GetEngine(ctx).Delete(&ActionScheduleSpec{RepoID: id}); err != nil {
- return err
- }
+ if _, err := db.GetEngine(ctx).Delete(&ActionScheduleSpec{RepoID: id}); err != nil {
+ return err
+ }
- return committer.Commit()
+ return nil
+ })
}
func CleanRepoScheduleTasks(ctx context.Context, repo *repo_model.Repository) ([]*ActionRunJob, error) {
diff --git a/models/actions/task.go b/models/actions/task.go
index e0756b10c2..c1306a8418 100644
--- a/models/actions/task.go
+++ b/models/actions/task.go
@@ -352,78 +352,70 @@ func UpdateTaskByState(ctx context.Context, runnerID int64, state *runnerv1.Task
stepStates[v.Id] = v
}
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return nil, err
- }
- defer committer.Close()
-
- e := db.GetEngine(ctx)
-
- task := &ActionTask{}
- if has, err := e.ID(state.Id).Get(task); err != nil {
- return nil, err
- } else if !has {
- return nil, util.ErrNotExist
- } else if runnerID != task.RunnerID {
- return nil, errors.New("invalid runner for task")
- }
-
- if task.Status.IsDone() {
- // the state is final, do nothing
- return task, nil
- }
+ return db.WithTx2(ctx, func(ctx context.Context) (*ActionTask, error) {
+ e := db.GetEngine(ctx)
- // state.Result is not unspecified means the task is finished
- if state.Result != runnerv1.Result_RESULT_UNSPECIFIED {
- task.Status = Status(state.Result)
- task.Stopped = timeutil.TimeStamp(state.StoppedAt.AsTime().Unix())
- if err := UpdateTask(ctx, task, "status", "stopped"); err != nil {
+ task := &ActionTask{}
+ if has, err := e.ID(state.Id).Get(task); err != nil {
return nil, err
+ } else if !has {
+ return nil, util.ErrNotExist
+ } else if runnerID != task.RunnerID {
+ return nil, errors.New("invalid runner for task")
}
- if _, err := UpdateRunJob(ctx, &ActionRunJob{
- ID: task.JobID,
- Status: task.Status,
- Stopped: task.Stopped,
- }, nil); err != nil {
- return nil, err
- }
- } else {
- // Force update ActionTask.Updated to avoid the task being judged as a zombie task
- task.Updated = timeutil.TimeStampNow()
- if err := UpdateTask(ctx, task, "updated"); err != nil {
- return nil, err
- }
- }
-
- if err := task.LoadAttributes(ctx); err != nil {
- return nil, err
- }
- for _, step := range task.Steps {
- var result runnerv1.Result
- if v, ok := stepStates[step.Index]; ok {
- result = v.Result
- step.LogIndex = v.LogIndex
- step.LogLength = v.LogLength
- step.Started = convertTimestamp(v.StartedAt)
- step.Stopped = convertTimestamp(v.StoppedAt)
+ if task.Status.IsDone() {
+ // the state is final, do nothing
+ return task, nil
}
- if result != runnerv1.Result_RESULT_UNSPECIFIED {
- step.Status = Status(result)
- } else if step.Started != 0 {
- step.Status = StatusRunning
+
+ // state.Result is not unspecified means the task is finished
+ if state.Result != runnerv1.Result_RESULT_UNSPECIFIED {
+ task.Status = Status(state.Result)
+ task.Stopped = timeutil.TimeStamp(state.StoppedAt.AsTime().Unix())
+ if err := UpdateTask(ctx, task, "status", "stopped"); err != nil {
+ return nil, err
+ }
+ if _, err := UpdateRunJob(ctx, &ActionRunJob{
+ ID: task.JobID,
+ Status: task.Status,
+ Stopped: task.Stopped,
+ }, nil); err != nil {
+ return nil, err
+ }
+ } else {
+ // Force update ActionTask.Updated to avoid the task being judged as a zombie task
+ task.Updated = timeutil.TimeStampNow()
+ if err := UpdateTask(ctx, task, "updated"); err != nil {
+ return nil, err
+ }
}
- if _, err := e.ID(step.ID).Update(step); err != nil {
+
+ if err := task.LoadAttributes(ctx); err != nil {
return nil, err
}
- }
- if err := committer.Commit(); err != nil {
- return nil, err
- }
+ for _, step := range task.Steps {
+ var result runnerv1.Result
+ if v, ok := stepStates[step.Index]; ok {
+ result = v.Result
+ step.LogIndex = v.LogIndex
+ step.LogLength = v.LogLength
+ step.Started = convertTimestamp(v.StartedAt)
+ step.Stopped = convertTimestamp(v.StoppedAt)
+ }
+ if result != runnerv1.Result_RESULT_UNSPECIFIED {
+ step.Status = Status(result)
+ } else if step.Started != 0 {
+ step.Status = StatusRunning
+ }
+ if _, err := e.ID(step.ID).Update(step); err != nil {
+ return nil, err
+ }
+ }
- return task, nil
+ return task, nil
+ })
}
func StopTask(ctx context.Context, taskID int64, status Status) error {
diff --git a/models/actions/tasks_version.go b/models/actions/tasks_version.go
index 96c5468c1a..b686ce2443 100644
--- a/models/actions/tasks_version.go
+++ b/models/actions/tasks_version.go
@@ -73,33 +73,29 @@ func increaseTasksVersionByScope(ctx context.Context, ownerID, repoID int64) err
}
func IncreaseTaskVersion(ctx context.Context, ownerID, repoID int64) error {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- // 1. increase global
- if err := increaseTasksVersionByScope(ctx, 0, 0); err != nil {
- log.Error("IncreaseTasksVersionByScope(Global): %v", err)
- return err
- }
-
- // 2. increase owner
- if ownerID > 0 {
- if err := increaseTasksVersionByScope(ctx, ownerID, 0); err != nil {
- log.Error("IncreaseTasksVersionByScope(Owner): %v", err)
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ // 1. increase global
+ if err := increaseTasksVersionByScope(ctx, 0, 0); err != nil {
+ log.Error("IncreaseTasksVersionByScope(Global): %v", err)
return err
}
- }
- // 3. increase repo
- if repoID > 0 {
- if err := increaseTasksVersionByScope(ctx, 0, repoID); err != nil {
- log.Error("IncreaseTasksVersionByScope(Repo): %v", err)
- return err
+ // 2. increase owner
+ if ownerID > 0 {
+ if err := increaseTasksVersionByScope(ctx, ownerID, 0); err != nil {
+ log.Error("IncreaseTasksVersionByScope(Owner): %v", err)
+ return err
+ }
+ }
+
+ // 3. increase repo
+ if repoID > 0 {
+ if err := increaseTasksVersionByScope(ctx, 0, repoID); err != nil {
+ log.Error("IncreaseTasksVersionByScope(Repo): %v", err)
+ return err
+ }
}
- }
- return committer.Commit()
+ return nil
+ })
}
diff --git a/models/activities/notification_list.go b/models/activities/notification_list.go
index b47f5dc404..6539e14ea2 100644
--- a/models/activities/notification_list.go
+++ b/models/activities/notification_list.go
@@ -70,17 +70,9 @@ func (opts FindNotificationOptions) ToOrders() string {
// for each watcher, or updates it if already exists
// receiverID > 0 just send to receiver, else send to all watcher
func CreateOrUpdateIssueNotifications(ctx context.Context, issueID, commentID, notificationAuthorID, receiverID int64) error {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- if err := createOrUpdateIssueNotifications(ctx, issueID, commentID, notificationAuthorID, receiverID); err != nil {
- return err
- }
-
- return committer.Commit()
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ return createOrUpdateIssueNotifications(ctx, issueID, commentID, notificationAuthorID, receiverID)
+ })
}
func createOrUpdateIssueNotifications(ctx context.Context, issueID, commentID, notificationAuthorID, receiverID int64) error {
diff --git a/models/asymkey/gpg_key.go b/models/asymkey/gpg_key.go
index 220f46ad1d..38de7cbda6 100644
--- a/models/asymkey/gpg_key.go
+++ b/models/asymkey/gpg_key.go
@@ -228,17 +228,10 @@ func DeleteGPGKey(ctx context.Context, doer *user_model.User, id int64) (err err
return fmt.Errorf("GetPublicKeyByID: %w", err)
}
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- if _, err = deleteGPGKey(ctx, key.KeyID); err != nil {
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ _, err = deleteGPGKey(ctx, key.KeyID)
return err
- }
-
- return committer.Commit()
+ })
}
func FindGPGKeyWithSubKeys(ctx context.Context, keyID string) ([]*GPGKey, error) {
diff --git a/models/asymkey/gpg_key_verify.go b/models/asymkey/gpg_key_verify.go
index 5ab2fd8081..55c64973b4 100644
--- a/models/asymkey/gpg_key_verify.go
+++ b/models/asymkey/gpg_key_verify.go
@@ -14,97 +14,76 @@ import (
"code.gitea.io/gitea/modules/log"
)
-// __________________ ________ ____ __.
-// / _____/\______ \/ _____/ | |/ _|____ ___.__.
-// / \ ___ | ___/ \ ___ | <_/ __ < | |
-// \ \_\ \| | \ \_\ \ | | \ ___/\___ |
-// \______ /|____| \______ / |____|__ \___ > ____|
-// \/ \/ \/ \/\/
-// ____ ____ .__ _____
-// \ \ / /___________|__|/ ____\__.__.
-// \ Y // __ \_ __ \ \ __< | |
-// \ /\ ___/| | \/ || | \___ |
-// \___/ \___ >__| |__||__| / ____|
-// \/ \/
-
// This file provides functions relating verifying gpg keys
// VerifyGPGKey marks a GPG key as verified
func VerifyGPGKey(ctx context.Context, ownerID int64, keyID, token, signature string) (string, error) {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return "", err
- }
- defer committer.Close()
-
- key := new(GPGKey)
-
- has, err := db.GetEngine(ctx).Where("owner_id = ? AND key_id = ?", ownerID, keyID).Get(key)
- if err != nil {
- return "", err
- } else if !has {
- return "", ErrGPGKeyNotExist{}
- }
-
- if err := key.LoadSubKeys(ctx); err != nil {
- return "", err
- }
+ return db.WithTx2(ctx, func(ctx context.Context) (string, error) {
+ key := new(GPGKey)
- sig, err := ExtractSignature(signature)
- if err != nil {
- return "", ErrGPGInvalidTokenSignature{
- ID: key.KeyID,
- Wrapped: err,
+ has, err := db.GetEngine(ctx).Where("owner_id = ? AND key_id = ?", ownerID, keyID).Get(key)
+ if err != nil {
+ return "", err
+ } else if !has {
+ return "", ErrGPGKeyNotExist{}
}
- }
- signer, err := hashAndVerifyWithSubKeys(sig, token, key)
- if err != nil {
- return "", ErrGPGInvalidTokenSignature{
- ID: key.KeyID,
- Wrapped: err,
+ if err := key.LoadSubKeys(ctx); err != nil {
+ return "", err
}
- }
- if signer == nil {
- signer, err = hashAndVerifyWithSubKeys(sig, token+"\n", key)
+
+ sig, err := ExtractSignature(signature)
if err != nil {
return "", ErrGPGInvalidTokenSignature{
ID: key.KeyID,
Wrapped: err,
}
}
- }
- if signer == nil {
- signer, err = hashAndVerifyWithSubKeys(sig, token+"\n\n", key)
+
+ signer, err := hashAndVerifyWithSubKeys(sig, token, key)
if err != nil {
return "", ErrGPGInvalidTokenSignature{
ID: key.KeyID,
Wrapped: err,
}
}
- }
-
- if signer == nil {
- log.Debug("VerifyGPGKey failed: no signer")
- return "", ErrGPGInvalidTokenSignature{
- ID: key.KeyID,
+ if signer == nil {
+ signer, err = hashAndVerifyWithSubKeys(sig, token+"\n", key)
+ if err != nil {
+ return "", ErrGPGInvalidTokenSignature{
+ ID: key.KeyID,
+ Wrapped: err,
+ }
+ }
+ }
+ if signer == nil {
+ signer, err = hashAndVerifyWithSubKeys(sig, token+"\n\n", key)
+ if err != nil {
+ return "", ErrGPGInvalidTokenSignature{
+ ID: key.KeyID,
+ Wrapped: err,
+ }
+ }
}
- }
- if signer.PrimaryKeyID != key.KeyID && signer.KeyID != key.KeyID {
- return "", ErrGPGKeyNotExist{}
- }
+ if signer == nil {
+ log.Debug("VerifyGPGKey failed: no signer")
+ return "", ErrGPGInvalidTokenSignature{
+ ID: key.KeyID,
+ }
+ }
- key.Verified = true
- if _, err := db.GetEngine(ctx).ID(key.ID).SetExpr("verified", true).Update(new(GPGKey)); err != nil {
- return "", err
- }
+ if signer.PrimaryKeyID != key.KeyID && signer.KeyID != key.KeyID {
+ return "", ErrGPGKeyNotExist{}
+ }
- if err := committer.Commit(); err != nil {
- return "", err
- }
+ key.Verified = true
+ if _, err := db.GetEngine(ctx).ID(key.ID).SetExpr("verified", true).Update(new(GPGKey)); err != nil {
+ return "", err
+ }
- return key.KeyID, nil
+ return key.KeyID, nil
+ })
}
// VerificationToken returns token for the user that will be valid in minutes (time)
diff --git a/models/asymkey/ssh_key.go b/models/asymkey/ssh_key.go
index dd94070fb9..87205f0651 100644
--- a/models/asymkey/ssh_key.go
+++ b/models/asymkey/ssh_key.go
@@ -99,40 +99,36 @@ func AddPublicKey(ctx context.Context, ownerID int64, name, content string, auth
return nil, err
}
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return nil, err
- }
- defer committer.Close()
-
- if err := checkKeyFingerprint(ctx, fingerprint); err != nil {
- return nil, err
- }
+ return db.WithTx2(ctx, func(ctx context.Context) (*PublicKey, error) {
+ if err := checkKeyFingerprint(ctx, fingerprint); err != nil {
+ return nil, err
+ }
- // Key name of same user cannot be duplicated.
- has, err := db.GetEngine(ctx).
- Where("owner_id = ? AND name = ?", ownerID, name).
- Get(new(PublicKey))
- if err != nil {
- return nil, err
- } else if has {
- return nil, ErrKeyNameAlreadyUsed{ownerID, name}
- }
+ // Key name of same user cannot be duplicated.
+ has, err := db.GetEngine(ctx).
+ Where("owner_id = ? AND name = ?", ownerID, name).
+ Get(new(PublicKey))
+ if err != nil {
+ return nil, err
+ } else if has {
+ return nil, ErrKeyNameAlreadyUsed{ownerID, name}
+ }
- key := &PublicKey{
- OwnerID: ownerID,
- Name: name,
- Fingerprint: fingerprint,
- Content: content,
- Mode: perm.AccessModeWrite,
- Type: KeyTypeUser,
- LoginSourceID: authSourceID,
- }
- if err = addKey(ctx, key); err != nil {
- return nil, fmt.Errorf("addKey: %w", err)
- }
+ key := &PublicKey{
+ OwnerID: ownerID,
+ Name: name,
+ Fingerprint: fingerprint,
+ Content: content,
+ Mode: perm.AccessModeWrite,
+ Type: KeyTypeUser,
+ LoginSourceID: authSourceID,
+ }
+ if err = addKey(ctx, key); err != nil {
+ return nil, fmt.Errorf("addKey: %w", err)
+ }
- return key, committer.Commit()
+ return key, nil
+ })
}
// GetPublicKeyByID returns public key by given ID.
@@ -288,33 +284,24 @@ func PublicKeyIsExternallyManaged(ctx context.Context, id int64) (bool, error) {
// deleteKeysMarkedForDeletion returns true if ssh keys needs update
func deleteKeysMarkedForDeletion(ctx context.Context, keys []string) (bool, error) {
- // Start session
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return false, err
- }
- defer committer.Close()
-
- // Delete keys marked for deletion
- var sshKeysNeedUpdate bool
- for _, KeyToDelete := range keys {
- key, err := SearchPublicKeyByContent(ctx, KeyToDelete)
- if err != nil {
- log.Error("SearchPublicKeyByContent: %v", err)
- continue
- }
- if _, err = db.DeleteByID[PublicKey](ctx, key.ID); err != nil {
- log.Error("DeleteByID[PublicKey]: %v", err)
- continue
+ return db.WithTx2(ctx, func(ctx context.Context) (bool, error) {
+ // Delete keys marked for deletion
+ var sshKeysNeedUpdate bool
+ for _, KeyToDelete := range keys {
+ key, err := SearchPublicKeyByContent(ctx, KeyToDelete)
+ if err != nil {
+ log.Error("SearchPublicKeyByContent: %v", err)
+ continue
+ }
+ if _, err = db.DeleteByID[PublicKey](ctx, key.ID); err != nil {
+ log.Error("DeleteByID[PublicKey]: %v", err)
+ continue
+ }
+ sshKeysNeedUpdate = true
}
- sshKeysNeedUpdate = true
- }
- if err := committer.Commit(); err != nil {
- return false, err
- }
-
- return sshKeysNeedUpdate, nil
+ return sshKeysNeedUpdate, nil
+ })
}
// AddPublicKeysBySource add a users public keys. Returns true if there are changes.
diff --git a/models/asymkey/ssh_key_deploy.go b/models/asymkey/ssh_key_deploy.go
index 923c5020ed..4ab84eabcf 100644
--- a/models/asymkey/ssh_key_deploy.go
+++ b/models/asymkey/ssh_key_deploy.go
@@ -125,39 +125,35 @@ func AddDeployKey(ctx context.Context, repoID int64, name, content string, readO
accessMode = perm.AccessModeWrite
}
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return nil, err
- }
- defer committer.Close()
-
- pkey, exist, err := db.Get[PublicKey](ctx, builder.Eq{"fingerprint": fingerprint})
- if err != nil {
- return nil, err
- } else if exist {
- if pkey.Type != KeyTypeDeploy {
- return nil, ErrKeyAlreadyExist{0, fingerprint, ""}
- }
- } else {
- // First time use this deploy key.
- pkey = &PublicKey{
- Fingerprint: fingerprint,
- Mode: accessMode,
- Type: KeyTypeDeploy,
- Content: content,
- Name: name,
+ return db.WithTx2(ctx, func(ctx context.Context) (*DeployKey, error) {
+ pkey, exist, err := db.Get[PublicKey](ctx, builder.Eq{"fingerprint": fingerprint})
+ if err != nil {
+ return nil, err
+ } else if exist {
+ if pkey.Type != KeyTypeDeploy {
+ return nil, ErrKeyAlreadyExist{0, fingerprint, ""}
+ }
+ } else {
+ // First time use this deploy key.
+ pkey = &PublicKey{
+ Fingerprint: fingerprint,
+ Mode: accessMode,
+ Type: KeyTypeDeploy,
+ Content: content,
+ Name: name,
+ }
+ if err = addKey(ctx, pkey); err != nil {
+ return nil, fmt.Errorf("addKey: %w", err)
+ }
}
- if err = addKey(ctx, pkey); err != nil {
- return nil, fmt.Errorf("addKey: %w", err)
- }
- }
- key, err := addDeployKey(ctx, pkey.ID, repoID, name, pkey.Fingerprint, accessMode)
- if err != nil {
- return nil, err
- }
+ key, err := addDeployKey(ctx, pkey.ID, repoID, name, pkey.Fingerprint, accessMode)
+ if err != nil {
+ return nil, err
+ }
- return key, committer.Commit()
+ return key, nil
+ })
}
// GetDeployKeyByID returns deploy key by given ID.
diff --git a/models/asymkey/ssh_key_verify.go b/models/asymkey/ssh_key_verify.go
index 0cf29ca9f1..04917239ee 100644
--- a/models/asymkey/ssh_key_verify.go
+++ b/models/asymkey/ssh_key_verify.go
@@ -15,41 +15,33 @@ import (
// VerifySSHKey marks a SSH key as verified
func VerifySSHKey(ctx context.Context, ownerID int64, fingerprint, token, signature string) (string, error) {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return "", err
- }
- defer committer.Close()
-
- key := new(PublicKey)
-
- has, err := db.GetEngine(ctx).Where("owner_id = ? AND fingerprint = ?", ownerID, fingerprint).Get(key)
- if err != nil {
- return "", err
- } else if !has {
- return "", ErrKeyNotExist{}
- }
-
- err = sshsig.Verify(strings.NewReader(token), []byte(signature), []byte(key.Content), "gitea")
- if err != nil {
- // edge case for Windows based shells that will add CR LF if piped to ssh-keygen command
- // see https://github.com/PowerShell/PowerShell/issues/5974
- if sshsig.Verify(strings.NewReader(token+"\r\n"), []byte(signature), []byte(key.Content), "gitea") != nil {
- log.Debug("VerifySSHKey sshsig.Verify failed: %v", err)
- return "", ErrSSHInvalidTokenSignature{
- Fingerprint: key.Fingerprint,
- }
+ return db.WithTx2(ctx, func(ctx context.Context) (string, error) {
+ key := new(PublicKey)
+
+ has, err := db.GetEngine(ctx).Where("owner_id = ? AND fingerprint = ?", ownerID, fingerprint).Get(key)
+ if err != nil {
+ return "", err
+ } else if !has {
+ return "", ErrKeyNotExist{}
}
- }
- key.Verified = true
- if _, err := db.GetEngine(ctx).ID(key.ID).Cols("verified").Update(key); err != nil {
- return "", err
- }
+ err = sshsig.Verify(strings.NewReader(token), []byte(signature), []byte(key.Content), "gitea")
+ if err != nil {
+ // edge case for Windows based shells that will add CR LF if piped to ssh-keygen command
+ // see https://github.com/PowerShell/PowerShell/issues/5974
+ if sshsig.Verify(strings.NewReader(token+"\r\n"), []byte(signature), []byte(key.Content), "gitea") != nil {
+ log.Debug("VerifySSHKey sshsig.Verify failed: %v", err)
+ return "", ErrSSHInvalidTokenSignature{
+ Fingerprint: key.Fingerprint,
+ }
+ }
+ }
- if err := committer.Commit(); err != nil {
- return "", err
- }
+ key.Verified = true
+ if _, err := db.GetEngine(ctx).ID(key.ID).Cols("verified").Update(key); err != nil {
+ return "", err
+ }
- return key.Fingerprint, nil
+ return key.Fingerprint, nil
+ })
}
diff --git a/models/auth/oauth2.go b/models/auth/oauth2.go
index 55af4e9036..d664841306 100644
--- a/models/auth/oauth2.go
+++ b/models/auth/oauth2.go
@@ -289,35 +289,31 @@ type UpdateOAuth2ApplicationOptions struct {
// UpdateOAuth2Application updates an oauth2 application
func UpdateOAuth2Application(ctx context.Context, opts UpdateOAuth2ApplicationOptions) (*OAuth2Application, error) {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return nil, err
- }
- defer committer.Close()
-
- app, err := GetOAuth2ApplicationByID(ctx, opts.ID)
- if err != nil {
- return nil, err
- }
- if app.UID != opts.UserID {
- return nil, errors.New("UID mismatch")
- }
- builtinApps := BuiltinApplications()
- if _, builtin := builtinApps[app.ClientID]; builtin {
- return nil, fmt.Errorf("failed to edit OAuth2 application: application is locked: %s", app.ClientID)
- }
+ return db.WithTx2(ctx, func(ctx context.Context) (*OAuth2Application, error) {
+ app, err := GetOAuth2ApplicationByID(ctx, opts.ID)
+ if err != nil {
+ return nil, err
+ }
+ if app.UID != opts.UserID {
+ return nil, errors.New("UID mismatch")
+ }
+ builtinApps := BuiltinApplications()
+ if _, builtin := builtinApps[app.ClientID]; builtin {
+ return nil, fmt.Errorf("failed to edit OAuth2 application: application is locked: %s", app.ClientID)
+ }
- app.Name = opts.Name
- app.RedirectURIs = opts.RedirectURIs
- app.ConfidentialClient = opts.ConfidentialClient
- app.SkipSecondaryAuthorization = opts.SkipSecondaryAuthorization
+ app.Name = opts.Name
+ app.RedirectURIs = opts.RedirectURIs
+ app.ConfidentialClient = opts.ConfidentialClient
+ app.SkipSecondaryAuthorization = opts.SkipSecondaryAuthorization
- if err = updateOAuth2Application(ctx, app); err != nil {
- return nil, err
- }
- app.ClientSecret = ""
+ if err = updateOAuth2Application(ctx, app); err != nil {
+ return nil, err
+ }
+ app.ClientSecret = ""
- return app, committer.Commit()
+ return app, nil
+ })
}
func updateOAuth2Application(ctx context.Context, app *OAuth2Application) error {
@@ -358,23 +354,17 @@ func deleteOAuth2Application(ctx context.Context, id, userid int64) error {
// DeleteOAuth2Application deletes the application with the given id and the grants and auth codes related to it. It checks if the userid was the creator of the app.
func DeleteOAuth2Application(ctx context.Context, id, userid int64) error {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
- app, err := GetOAuth2ApplicationByID(ctx, id)
- if err != nil {
- return err
- }
- builtinApps := BuiltinApplications()
- if _, builtin := builtinApps[app.ClientID]; builtin {
- return fmt.Errorf("failed to delete OAuth2 application: application is locked: %s", app.ClientID)
- }
- if err := deleteOAuth2Application(ctx, id, userid); err != nil {
- return err
- }
- return committer.Commit()
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ app, err := GetOAuth2ApplicationByID(ctx, id)
+ if err != nil {
+ return err
+ }
+ builtinApps := BuiltinApplications()
+ if _, builtin := builtinApps[app.ClientID]; builtin {
+ return fmt.Errorf("failed to delete OAuth2 application: application is locked: %s", app.ClientID)
+ }
+ return deleteOAuth2Application(ctx, id, userid)
+ })
}
//////////////////////////////////////////////////////
diff --git a/models/auth/session.go b/models/auth/session.go
index 75a205f702..0378d0ec6f 100644
--- a/models/auth/session.go
+++ b/models/auth/session.go
@@ -35,26 +35,22 @@ func UpdateSession(ctx context.Context, key string, data []byte) error {
// ReadSession reads the data for the provided session
func ReadSession(ctx context.Context, key string) (*Session, error) {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return nil, err
- }
- defer committer.Close()
-
- session, exist, err := db.Get[Session](ctx, builder.Eq{"`key`": key})
- if err != nil {
- return nil, err
- } else if !exist {
- session = &Session{
- Key: key,
- Expiry: timeutil.TimeStampNow(),
- }
- if err := db.Insert(ctx, session); err != nil {
+ return db.WithTx2(ctx, func(ctx context.Context) (*Session, error) {
+ session, exist, err := db.Get[Session](ctx, builder.Eq{"`key`": key})
+ if err != nil {
return nil, err
+ } else if !exist {
+ session = &Session{
+ Key: key,
+ Expiry: timeutil.TimeStampNow(),
+ }
+ if err := db.Insert(ctx, session); err != nil {
+ return nil, err
+ }
}
- }
- return session, committer.Commit()
+ return session, nil
+ })
}
// ExistSession checks if a session exists
@@ -72,40 +68,36 @@ func DestroySession(ctx context.Context, key string) error {
// RegenerateSession regenerates a session from the old id
func RegenerateSession(ctx context.Context, oldKey, newKey string) (*Session, error) {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return nil, err
- }
- defer committer.Close()
-
- if has, err := db.Exist[Session](ctx, builder.Eq{"`key`": newKey}); err != nil {
- return nil, err
- } else if has {
- return nil, fmt.Errorf("session Key: %s already exists", newKey)
- }
-
- if has, err := db.Exist[Session](ctx, builder.Eq{"`key`": oldKey}); err != nil {
- return nil, err
- } else if !has {
- if err := db.Insert(ctx, &Session{
- Key: oldKey,
- Expiry: timeutil.TimeStampNow(),
- }); err != nil {
+ return db.WithTx2(ctx, func(ctx context.Context) (*Session, error) {
+ if has, err := db.Exist[Session](ctx, builder.Eq{"`key`": newKey}); err != nil {
+ return nil, err
+ } else if has {
+ return nil, fmt.Errorf("session Key: %s already exists", newKey)
+ }
+
+ if has, err := db.Exist[Session](ctx, builder.Eq{"`key`": oldKey}); err != nil {
return nil, err
+ } else if !has {
+ if err := db.Insert(ctx, &Session{
+ Key: oldKey,
+ Expiry: timeutil.TimeStampNow(),
+ }); err != nil {
+ return nil, err
+ }
}
- }
- if _, err := db.Exec(ctx, "UPDATE "+db.TableName(&Session{})+" SET `key` = ? WHERE `key`=?", newKey, oldKey); err != nil {
- return nil, err
- }
+ if _, err := db.Exec(ctx, "UPDATE "+db.TableName(&Session{})+" SET `key` = ? WHERE `key`=?", newKey, oldKey); err != nil {
+ return nil, err
+ }
- s, _, err := db.Get[Session](ctx, builder.Eq{"`key`": newKey})
- if err != nil {
- // is not exist, it should be impossible
- return nil, err
- }
+ s, _, err := db.Get[Session](ctx, builder.Eq{"`key`": newKey})
+ if err != nil {
+ // is not exist, it should be impossible
+ return nil, err
+ }
- return s, committer.Commit()
+ return s, nil
+ })
}
// CountSessions returns the number of sessions
diff --git a/models/git/commit_status.go b/models/git/commit_status.go
index f85e1b15e5..e255bca5d0 100644
--- a/models/git/commit_status.go
+++ b/models/git/commit_status.go
@@ -470,35 +470,31 @@ func NewCommitStatus(ctx context.Context, opts NewCommitStatusOptions) error {
return fmt.Errorf("NewCommitStatus[%s, %s]: no user specified", opts.Repo.FullName(), opts.SHA)
}
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return fmt.Errorf("NewCommitStatus[repo_id: %d, user_id: %d, sha: %s]: %w", opts.Repo.ID, opts.Creator.ID, opts.SHA, err)
- }
- defer committer.Close()
-
- // Get the next Status Index
- idx, err := GetNextCommitStatusIndex(ctx, opts.Repo.ID, opts.SHA.String())
- if err != nil {
- return fmt.Errorf("generate commit status index failed: %w", err)
- }
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ // Get the next Status Index
+ idx, err := GetNextCommitStatusIndex(ctx, opts.Repo.ID, opts.SHA.String())
+ if err != nil {
+ return fmt.Errorf("generate commit status index failed: %w", err)
+ }
- opts.CommitStatus.Description = strings.TrimSpace(opts.CommitStatus.Description)
- opts.CommitStatus.Context = strings.TrimSpace(opts.CommitStatus.Context)
- opts.CommitStatus.TargetURL = strings.TrimSpace(opts.CommitStatus.TargetURL)
- opts.CommitStatus.SHA = opts.SHA.String()
- opts.CommitStatus.CreatorID = opts.Creator.ID
- opts.CommitStatus.RepoID = opts.Repo.ID
- opts.CommitStatus.Index = idx
- log.Debug("NewCommitStatus[%s, %s]: %d", opts.Repo.FullName(), opts.SHA, opts.CommitStatus.Index)
+ opts.CommitStatus.Description = strings.TrimSpace(opts.CommitStatus.Description)
+ opts.CommitStatus.Context = strings.TrimSpace(opts.CommitStatus.Context)
+ opts.CommitStatus.TargetURL = strings.TrimSpace(opts.CommitStatus.TargetURL)
+ opts.CommitStatus.SHA = opts.SHA.String()
+ opts.CommitStatus.CreatorID = opts.Creator.ID
+ opts.CommitStatus.RepoID = opts.Repo.ID
+ opts.CommitStatus.Index = idx
+ log.Debug("NewCommitStatus[%s, %s]: %d", opts.Repo.FullName(), opts.SHA, opts.CommitStatus.Index)
- opts.CommitStatus.ContextHash = hashCommitStatusContext(opts.CommitStatus.Context)
+ opts.CommitStatus.ContextHash = hashCommitStatusContext(opts.CommitStatus.Context)
- // Insert new CommitStatus
- if _, err = db.GetEngine(ctx).Insert(opts.CommitStatus); err != nil {
- return fmt.Errorf("insert CommitStatus[%s, %s]: %w", opts.Repo.FullName(), opts.SHA, err)
- }
+ // Insert new CommitStatus
+ if err = db.Insert(ctx, opts.CommitStatus); err != nil {
+ return fmt.Errorf("insert CommitStatus[%s, %s]: %w", opts.Repo.FullName(), opts.SHA, err)
+ }
- return committer.Commit()
+ return nil
+ })
}
// SignCommitWithStatuses represents a commit with validation of signature and status state.
diff --git a/models/git/lfs.go b/models/git/lfs.go
index e4fa2b446a..c471baf588 100644
--- a/models/git/lfs.go
+++ b/models/git/lfs.go
@@ -135,25 +135,18 @@ var ErrLFSObjectNotExist = db.ErrNotExist{Resource: "LFS Meta object"}
// NewLFSMetaObject stores a given populated LFSMetaObject structure in the database
// if it is not already present.
func NewLFSMetaObject(ctx context.Context, repoID int64, p lfs.Pointer) (*LFSMetaObject, error) {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return nil, err
- }
- defer committer.Close()
-
m, exist, err := db.Get[LFSMetaObject](ctx, builder.Eq{"repository_id": repoID, "oid": p.Oid})
if err != nil {
return nil, err
} else if exist {
- return m, committer.Commit()
+ return m, nil
}
m = &LFSMetaObject{Pointer: p, RepositoryID: repoID}
if err = db.Insert(ctx, m); err != nil {
return nil, err
}
-
- return m, committer.Commit()
+ return m, nil
}
// GetLFSMetaObjectByOid selects a LFSMetaObject entry from database by its OID.
diff --git a/models/git/lfs_lock.go b/models/git/lfs_lock.go
index 07ce7d4abf..c5f9a4e6de 100644
--- a/models/git/lfs_lock.go
+++ b/models/git/lfs_lock.go
@@ -70,32 +70,28 @@ func (l *LFSLock) LoadOwner(ctx context.Context) error {
// CreateLFSLock creates a new lock.
func CreateLFSLock(ctx context.Context, repo *repo_model.Repository, lock *LFSLock) (*LFSLock, error) {
- dbCtx, committer, err := db.TxContext(ctx)
- if err != nil {
- return nil, err
- }
- defer committer.Close()
-
- if err := CheckLFSAccessForRepo(dbCtx, lock.OwnerID, repo, perm.AccessModeWrite); err != nil {
- return nil, err
- }
+ return db.WithTx2(ctx, func(ctx context.Context) (*LFSLock, error) {
+ if err := CheckLFSAccessForRepo(ctx, lock.OwnerID, repo, perm.AccessModeWrite); err != nil {
+ return nil, err
+ }
- lock.Path = util.PathJoinRel(lock.Path)
- lock.RepoID = repo.ID
+ lock.Path = util.PathJoinRel(lock.Path)
+ lock.RepoID = repo.ID
- l, err := GetLFSLock(dbCtx, repo, lock.Path)
- if err == nil {
- return l, ErrLFSLockAlreadyExist{lock.RepoID, lock.Path}
- }
- if !IsErrLFSLockNotExist(err) {
- return nil, err
- }
+ l, err := GetLFSLock(ctx, repo, lock.Path)
+ if err == nil {
+ return l, ErrLFSLockAlreadyExist{lock.RepoID, lock.Path}
+ }
+ if !IsErrLFSLockNotExist(err) {
+ return nil, err
+ }
- if err := db.Insert(dbCtx, lock); err != nil {
- return nil, err
- }
+ if err := db.Insert(ctx, lock); err != nil {
+ return nil, err
+ }
- return lock, committer.Commit()
+ return lock, nil
+ })
}
// GetLFSLock returns release by given path.
@@ -163,30 +159,26 @@ func CountLFSLockByRepoID(ctx context.Context, repoID int64) (int64, error) {
// DeleteLFSLockByID deletes a lock by given ID.
func DeleteLFSLockByID(ctx context.Context, id int64, repo *repo_model.Repository, u *user_model.User, force bool) (*LFSLock, error) {
- dbCtx, committer, err := db.TxContext(ctx)
- if err != nil {
- return nil, err
- }
- defer committer.Close()
-
- lock, err := GetLFSLockByID(dbCtx, id)
- if err != nil {
- return nil, err
- }
+ return db.WithTx2(ctx, func(ctx context.Context) (*LFSLock, error) {
+ lock, err := GetLFSLockByID(ctx, id)
+ if err != nil {
+ return nil, err
+ }
- if err := CheckLFSAccessForRepo(dbCtx, u.ID, repo, perm.AccessModeWrite); err != nil {
- return nil, err
- }
+ if err := CheckLFSAccessForRepo(ctx, u.ID, repo, perm.AccessModeWrite); err != nil {
+ return nil, err
+ }
- if !force && u.ID != lock.OwnerID {
- return nil, errors.New("user doesn't own lock and force flag is not set")
- }
+ if !force && u.ID != lock.OwnerID {
+ return nil, errors.New("user doesn't own lock and force flag is not set")
+ }
- if _, err := db.GetEngine(dbCtx).ID(id).Delete(new(LFSLock)); err != nil {
- return nil, err
- }
+ if _, err := db.GetEngine(ctx).ID(id).Delete(new(LFSLock)); err != nil {
+ return nil, err
+ }
- return lock, committer.Commit()
+ return lock, nil
+ })
}
// CheckLFSAccessForRepo check needed access mode base on action
diff --git a/models/issues/comment.go b/models/issues/comment.go
index 4fdb0c1808..d22f08fa87 100644
--- a/models/issues/comment.go
+++ b/models/issues/comment.go
@@ -766,81 +766,73 @@ func (c *Comment) CodeCommentLink(ctx context.Context) string {
// CreateComment creates comment with context
func CreateComment(ctx context.Context, opts *CreateCommentOptions) (_ *Comment, err error) {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return nil, err
- }
- defer committer.Close()
-
- e := db.GetEngine(ctx)
- var LabelID int64
- if opts.Label != nil {
- LabelID = opts.Label.ID
- }
+ return db.WithTx2(ctx, func(ctx context.Context) (*Comment, error) {
+ var LabelID int64
+ if opts.Label != nil {
+ LabelID = opts.Label.ID
+ }
- var commentMetaData *CommentMetaData
- if opts.ProjectColumnTitle != "" {
- commentMetaData = &CommentMetaData{
- ProjectColumnID: opts.ProjectColumnID,
- ProjectColumnTitle: opts.ProjectColumnTitle,
- ProjectTitle: opts.ProjectTitle,
+ var commentMetaData *CommentMetaData
+ if opts.ProjectColumnTitle != "" {
+ commentMetaData = &CommentMetaData{
+ ProjectColumnID: opts.ProjectColumnID,
+ ProjectColumnTitle: opts.ProjectColumnTitle,
+ ProjectTitle: opts.ProjectTitle,
+ }
}
- }
- comment := &Comment{
- Type: opts.Type,
- PosterID: opts.Doer.ID,
- Poster: opts.Doer,
- IssueID: opts.Issue.ID,
- LabelID: LabelID,
- OldMilestoneID: opts.OldMilestoneID,
- MilestoneID: opts.MilestoneID,
- OldProjectID: opts.OldProjectID,
- ProjectID: opts.ProjectID,
- TimeID: opts.TimeID,
- RemovedAssignee: opts.RemovedAssignee,
- AssigneeID: opts.AssigneeID,
- AssigneeTeamID: opts.AssigneeTeamID,
- CommitID: opts.CommitID,
- CommitSHA: opts.CommitSHA,
- Line: opts.LineNum,
- Content: opts.Content,
- OldTitle: opts.OldTitle,
- NewTitle: opts.NewTitle,
- OldRef: opts.OldRef,
- NewRef: opts.NewRef,
- DependentIssueID: opts.DependentIssueID,
- TreePath: opts.TreePath,
- ReviewID: opts.ReviewID,
- Patch: opts.Patch,
- RefRepoID: opts.RefRepoID,
- RefIssueID: opts.RefIssueID,
- RefCommentID: opts.RefCommentID,
- RefAction: opts.RefAction,
- RefIsPull: opts.RefIsPull,
- IsForcePush: opts.IsForcePush,
- Invalidated: opts.Invalidated,
- CommentMetaData: commentMetaData,
- }
- if _, err = e.Insert(comment); err != nil {
- return nil, err
- }
+ comment := &Comment{
+ Type: opts.Type,
+ PosterID: opts.Doer.ID,
+ Poster: opts.Doer,
+ IssueID: opts.Issue.ID,
+ LabelID: LabelID,
+ OldMilestoneID: opts.OldMilestoneID,
+ MilestoneID: opts.MilestoneID,
+ OldProjectID: opts.OldProjectID,
+ ProjectID: opts.ProjectID,
+ TimeID: opts.TimeID,
+ RemovedAssignee: opts.RemovedAssignee,
+ AssigneeID: opts.AssigneeID,
+ AssigneeTeamID: opts.AssigneeTeamID,
+ CommitID: opts.CommitID,
+ CommitSHA: opts.CommitSHA,
+ Line: opts.LineNum,
+ Content: opts.Content,
+ OldTitle: opts.OldTitle,
+ NewTitle: opts.NewTitle,
+ OldRef: opts.OldRef,
+ NewRef: opts.NewRef,
+ DependentIssueID: opts.DependentIssueID,
+ TreePath: opts.TreePath,
+ ReviewID: opts.ReviewID,
+ Patch: opts.Patch,
+ RefRepoID: opts.RefRepoID,
+ RefIssueID: opts.RefIssueID,
+ RefCommentID: opts.RefCommentID,
+ RefAction: opts.RefAction,
+ RefIsPull: opts.RefIsPull,
+ IsForcePush: opts.IsForcePush,
+ Invalidated: opts.Invalidated,
+ CommentMetaData: commentMetaData,
+ }
+ if err = db.Insert(ctx, comment); err != nil {
+ return nil, err
+ }
- if err = opts.Repo.LoadOwner(ctx); err != nil {
- return nil, err
- }
+ if err = opts.Repo.LoadOwner(ctx); err != nil {
+ return nil, err
+ }
- if err = updateCommentInfos(ctx, opts, comment); err != nil {
- return nil, err
- }
+ if err = updateCommentInfos(ctx, opts, comment); err != nil {
+ return nil, err
+ }
- if err = comment.AddCrossReferences(ctx, opts.Doer, false); err != nil {
- return nil, err
- }
- if err = committer.Commit(); err != nil {
- return nil, err
- }
- return comment, nil
+ if err = comment.AddCrossReferences(ctx, opts.Doer, false); err != nil {
+ return nil, err
+ }
+ return comment, nil
+ })
}
func updateCommentInfos(ctx context.Context, opts *CreateCommentOptions, comment *Comment) (err error) {
@@ -1092,33 +1084,21 @@ func UpdateCommentInvalidate(ctx context.Context, c *Comment) error {
// UpdateComment updates information of comment.
func UpdateComment(ctx context.Context, c *Comment, contentVersion int, doer *user_model.User) error {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
- sess := db.GetEngine(ctx)
-
- c.ContentVersion = contentVersion + 1
-
- affected, err := sess.ID(c.ID).AllCols().Where("content_version = ?", contentVersion).Update(c)
- if err != nil {
- return err
- }
- if affected == 0 {
- return ErrCommentAlreadyChanged
- }
- if err := c.LoadIssue(ctx); err != nil {
- return err
- }
- if err := c.AddCrossReferences(ctx, doer, true); err != nil {
- return err
- }
- if err := committer.Commit(); err != nil {
- return fmt.Errorf("Commit: %w", err)
- }
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ c.ContentVersion = contentVersion + 1
- return nil
+ affected, err := db.GetEngine(ctx).ID(c.ID).AllCols().Where("content_version = ?", contentVersion).Update(c)
+ if err != nil {
+ return err
+ }
+ if affected == 0 {
+ return ErrCommentAlreadyChanged
+ }
+ if err := c.LoadIssue(ctx); err != nil {
+ return err
+ }
+ return c.AddCrossReferences(ctx, doer, true)
+ })
}
// DeleteComment deletes the comment
@@ -1277,31 +1257,28 @@ func InsertIssueComments(ctx context.Context, comments []*Comment) error {
return comment.IssueID, true
})
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
- for _, comment := range comments {
- if _, err := db.GetEngine(ctx).NoAutoTime().Insert(comment); err != nil {
- return err
- }
-
- for _, reaction := range comment.Reactions {
- reaction.IssueID = comment.IssueID
- reaction.CommentID = comment.ID
- }
- if len(comment.Reactions) > 0 {
- if err := db.Insert(ctx, comment.Reactions); err != nil {
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ for _, comment := range comments {
+ if _, err := db.GetEngine(ctx).NoAutoTime().Insert(comment); err != nil {
return err
}
+
+ for _, reaction := range comment.Reactions {
+ reaction.IssueID = comment.IssueID
+ reaction.CommentID = comment.ID
+ }
+ if len(comment.Reactions) > 0 {
+ if err := db.Insert(ctx, comment.Reactions); err != nil {
+ return err
+ }
+ }
}
- }
- for _, issueID := range issueIDs {
- if err := UpdateIssueNumComments(ctx, issueID); err != nil {
- return err
+ for _, issueID := range issueIDs {
+ if err := UpdateIssueNumComments(ctx, issueID); err != nil {
+ return err
+ }
}
- }
- return committer.Commit()
+ return nil
+ })
}
diff --git a/models/issues/dependency.go b/models/issues/dependency.go
index 146dd1887d..0eaa47e359 100644
--- a/models/issues/dependency.go
+++ b/models/issues/dependency.go
@@ -128,79 +128,64 @@ const (
// CreateIssueDependency creates a new dependency for an issue
func CreateIssueDependency(ctx context.Context, user *user_model.User, issue, dep *Issue) error {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- // Check if it already exists
- exists, err := issueDepExists(ctx, issue.ID, dep.ID)
- if err != nil {
- return err
- }
- if exists {
- return ErrDependencyExists{issue.ID, dep.ID}
- }
- // And if it would be circular
- circular, err := issueDepExists(ctx, dep.ID, issue.ID)
- if err != nil {
- return err
- }
- if circular {
- return ErrCircularDependency{issue.ID, dep.ID}
- }
-
- if err := db.Insert(ctx, &IssueDependency{
- UserID: user.ID,
- IssueID: issue.ID,
- DependencyID: dep.ID,
- }); err != nil {
- return err
- }
-
- // Add comment referencing the new dependency
- if err = createIssueDependencyComment(ctx, user, issue, dep, true); err != nil {
- return err
- }
-
- return committer.Commit()
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ // Check if it already exists
+ exists, err := issueDepExists(ctx, issue.ID, dep.ID)
+ if err != nil {
+ return err
+ }
+ if exists {
+ return ErrDependencyExists{issue.ID, dep.ID}
+ }
+ // And if it would be circular
+ circular, err := issueDepExists(ctx, dep.ID, issue.ID)
+ if err != nil {
+ return err
+ }
+ if circular {
+ return ErrCircularDependency{issue.ID, dep.ID}
+ }
+
+ if err := db.Insert(ctx, &IssueDependency{
+ UserID: user.ID,
+ IssueID: issue.ID,
+ DependencyID: dep.ID,
+ }); err != nil {
+ return err
+ }
+
+ // Add comment referencing the new dependency
+ return createIssueDependencyComment(ctx, user, issue, dep, true)
+ })
}
// RemoveIssueDependency removes a dependency from an issue
func RemoveIssueDependency(ctx context.Context, user *user_model.User, issue, dep *Issue, depType DependencyType) (err error) {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- var issueDepToDelete IssueDependency
-
- switch depType {
- case DependencyTypeBlockedBy:
- issueDepToDelete = IssueDependency{IssueID: issue.ID, DependencyID: dep.ID}
- case DependencyTypeBlocking:
- issueDepToDelete = IssueDependency{IssueID: dep.ID, DependencyID: issue.ID}
- default:
- return ErrUnknownDependencyType{depType}
- }
-
- affected, err := db.GetEngine(ctx).Delete(&issueDepToDelete)
- if err != nil {
- return err
- }
-
- // If we deleted nothing, the dependency did not exist
- if affected <= 0 {
- return ErrDependencyNotExists{issue.ID, dep.ID}
- }
-
- // Add comment referencing the removed dependency
- if err = createIssueDependencyComment(ctx, user, issue, dep, false); err != nil {
- return err
- }
- return committer.Commit()
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ var issueDepToDelete IssueDependency
+
+ switch depType {
+ case DependencyTypeBlockedBy:
+ issueDepToDelete = IssueDependency{IssueID: issue.ID, DependencyID: dep.ID}
+ case DependencyTypeBlocking:
+ issueDepToDelete = IssueDependency{IssueID: dep.ID, DependencyID: issue.ID}
+ default:
+ return ErrUnknownDependencyType{depType}
+ }
+
+ affected, err := db.GetEngine(ctx).Delete(&issueDepToDelete)
+ if err != nil {
+ return err
+ }
+
+ // If we deleted nothing, the dependency did not exist
+ if affected <= 0 {
+ return ErrDependencyNotExists{issue.ID, dep.ID}
+ }
+
+ // Add comment referencing the removed dependency
+ return createIssueDependencyComment(ctx, user, issue, dep, false)
+ })
}
// Check if the dependency already exists
diff --git a/models/issues/issue.go b/models/issues/issue.go
index a86d50ca9d..ef651359ab 100644
--- a/models/issues/issue.go
+++ b/models/issues/issue.go
@@ -755,18 +755,14 @@ func (issue *Issue) HasOriginalAuthor() bool {
// InsertIssues insert issues to database
func InsertIssues(ctx context.Context, issues ...*Issue) error {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- for _, issue := range issues {
- if err := insertIssue(ctx, issue); err != nil {
- return err
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ for _, issue := range issues {
+ if err := insertIssue(ctx, issue); err != nil {
+ return err
+ }
}
- }
- return committer.Commit()
+ return nil
+ })
}
func insertIssue(ctx context.Context, issue *Issue) error {
diff --git a/models/issues/issue_index.go b/models/issues/issue_index.go
index 2eb61858bf..1fe4a08a09 100644
--- a/models/issues/issue_index.go
+++ b/models/issues/issue_index.go
@@ -12,20 +12,12 @@ import (
// RecalculateIssueIndexForRepo create issue_index for repo if not exist and
// update it based on highest index of existing issues assigned to a repo
func RecalculateIssueIndexForRepo(ctx context.Context, repoID int64) error {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ var maxIndex int64
+ if _, err := db.GetEngine(ctx).Select(" MAX(`index`)").Table("issue").Where("repo_id=?", repoID).Get(&maxIndex); err != nil {
+ return err
+ }
- var maxIndex int64
- if _, err = db.GetEngine(ctx).Select(" MAX(`index`)").Table("issue").Where("repo_id=?", repoID).Get(&maxIndex); err != nil {
- return err
- }
-
- if err = db.SyncMaxResourceIndex(ctx, "issue_index", repoID, maxIndex); err != nil {
- return err
- }
-
- return committer.Commit()
+ return db.SyncMaxResourceIndex(ctx, "issue_index", repoID, maxIndex)
+ })
}
diff --git a/models/issues/issue_label.go b/models/issues/issue_label.go
index f082079e07..151469a9b8 100644
--- a/models/issues/issue_label.go
+++ b/models/issues/issue_label.go
@@ -88,36 +88,28 @@ func NewIssueLabel(ctx context.Context, issue *Issue, label *Label, doer *user_m
return nil
}
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- if err = issue.LoadRepo(ctx); err != nil {
- return err
- }
-
- // Do NOT add invalid labels
- if issue.RepoID != label.RepoID && issue.Repo.OwnerID != label.OrgID {
- return nil
- }
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ if err = issue.LoadRepo(ctx); err != nil {
+ return err
+ }
- if err = RemoveDuplicateExclusiveIssueLabels(ctx, issue, label, doer); err != nil {
- return nil
- }
+ // Do NOT add invalid labels
+ if issue.RepoID != label.RepoID && issue.Repo.OwnerID != label.OrgID {
+ return nil
+ }
- if err = newIssueLabel(ctx, issue, label, doer); err != nil {
- return err
- }
+ if err = RemoveDuplicateExclusiveIssueLabels(ctx, issue, label, doer); err != nil {
+ return nil
+ }
- issue.isLabelsLoaded = false
- issue.Labels = nil
- if err = issue.LoadLabels(ctx); err != nil {
- return err
- }
+ if err = newIssueLabel(ctx, issue, label, doer); err != nil {
+ return err
+ }
- return committer.Commit()
+ issue.isLabelsLoaded = false
+ issue.Labels = nil
+ return issue.LoadLabels(ctx)
+ })
}
// newIssueLabels add labels to an issue. It will check if the labels are valid for the issue
@@ -151,24 +143,16 @@ func newIssueLabels(ctx context.Context, issue *Issue, labels []*Label, doer *us
// NewIssueLabels creates a list of issue-label relations.
func NewIssueLabels(ctx context.Context, issue *Issue, labels []*Label, doer *user_model.User) (err error) {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- if err = newIssueLabels(ctx, issue, labels, doer); err != nil {
- return err
- }
-
- // reload all labels
- issue.isLabelsLoaded = false
- issue.Labels = nil
- if err = issue.LoadLabels(ctx); err != nil {
- return err
- }
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ if err = newIssueLabels(ctx, issue, labels, doer); err != nil {
+ return err
+ }
- return committer.Commit()
+ // reload all labels
+ issue.isLabelsLoaded = false
+ issue.Labels = nil
+ return issue.LoadLabels(ctx)
+ })
}
func deleteIssueLabel(ctx context.Context, issue *Issue, label *Label, doer *user_model.User) (err error) {
@@ -365,35 +349,23 @@ func clearIssueLabels(ctx context.Context, issue *Issue, doer *user_model.User)
// ClearIssueLabels removes all issue labels as the given user.
// Triggers appropriate WebHooks, if any.
func ClearIssueLabels(ctx context.Context, issue *Issue, doer *user_model.User) (err error) {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- if err := issue.LoadRepo(ctx); err != nil {
- return err
- } else if err = issue.LoadPullRequest(ctx); err != nil {
- return err
- }
-
- perm, err := access_model.GetUserRepoPermission(ctx, issue.Repo, doer)
- if err != nil {
- return err
- }
- if !perm.CanWriteIssuesOrPulls(issue.IsPull) {
- return ErrRepoLabelNotExist{}
- }
-
- if err = clearIssueLabels(ctx, issue, doer); err != nil {
- return err
- }
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ if err := issue.LoadRepo(ctx); err != nil {
+ return err
+ } else if err = issue.LoadPullRequest(ctx); err != nil {
+ return err
+ }
- if err = committer.Commit(); err != nil {
- return fmt.Errorf("Commit: %w", err)
- }
+ perm, err := access_model.GetUserRepoPermission(ctx, issue.Repo, doer)
+ if err != nil {
+ return err
+ }
+ if !perm.CanWriteIssuesOrPulls(issue.IsPull) {
+ return ErrRepoLabelNotExist{}
+ }
- return nil
+ return clearIssueLabels(ctx, issue, doer)
+ })
}
type labelSorter []*Label
@@ -438,69 +410,61 @@ func RemoveDuplicateExclusiveLabels(labels []*Label) []*Label {
// ReplaceIssueLabels removes all current labels and add new labels to the issue.
// Triggers appropriate WebHooks, if any.
func ReplaceIssueLabels(ctx context.Context, issue *Issue, labels []*Label, doer *user_model.User) (err error) {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ if err = issue.LoadRepo(ctx); err != nil {
+ return err
+ }
- if err = issue.LoadRepo(ctx); err != nil {
- return err
- }
+ if err = issue.LoadLabels(ctx); err != nil {
+ return err
+ }
- if err = issue.LoadLabels(ctx); err != nil {
- return err
- }
+ labels = RemoveDuplicateExclusiveLabels(labels)
- labels = RemoveDuplicateExclusiveLabels(labels)
+ sort.Sort(labelSorter(labels))
+ sort.Sort(labelSorter(issue.Labels))
- sort.Sort(labelSorter(labels))
- sort.Sort(labelSorter(issue.Labels))
+ var toAdd, toRemove []*Label
- var toAdd, toRemove []*Label
+ addIndex, removeIndex := 0, 0
+ for addIndex < len(labels) && removeIndex < len(issue.Labels) {
+ addLabel := labels[addIndex]
+ removeLabel := issue.Labels[removeIndex]
+ if addLabel.ID == removeLabel.ID {
+ // Silently drop invalid labels
+ if removeLabel.RepoID != issue.RepoID && removeLabel.OrgID != issue.Repo.OwnerID {
+ toRemove = append(toRemove, removeLabel)
+ }
- addIndex, removeIndex := 0, 0
- for addIndex < len(labels) && removeIndex < len(issue.Labels) {
- addLabel := labels[addIndex]
- removeLabel := issue.Labels[removeIndex]
- if addLabel.ID == removeLabel.ID {
- // Silently drop invalid labels
- if removeLabel.RepoID != issue.RepoID && removeLabel.OrgID != issue.Repo.OwnerID {
+ addIndex++
+ removeIndex++
+ } else if addLabel.ID < removeLabel.ID {
+ // Only add if the label is valid
+ if addLabel.RepoID == issue.RepoID || addLabel.OrgID == issue.Repo.OwnerID {
+ toAdd = append(toAdd, addLabel)
+ }
+ addIndex++
+ } else {
toRemove = append(toRemove, removeLabel)
+ removeIndex++
}
-
- addIndex++
- removeIndex++
- } else if addLabel.ID < removeLabel.ID {
- // Only add if the label is valid
- if addLabel.RepoID == issue.RepoID || addLabel.OrgID == issue.Repo.OwnerID {
- toAdd = append(toAdd, addLabel)
- }
- addIndex++
- } else {
- toRemove = append(toRemove, removeLabel)
- removeIndex++
}
- }
- toAdd = append(toAdd, labels[addIndex:]...)
- toRemove = append(toRemove, issue.Labels[removeIndex:]...)
+ toAdd = append(toAdd, labels[addIndex:]...)
+ toRemove = append(toRemove, issue.Labels[removeIndex:]...)
- if len(toAdd) > 0 {
- if err = newIssueLabels(ctx, issue, toAdd, doer); err != nil {
- return fmt.Errorf("addLabels: %w", err)
+ if len(toAdd) > 0 {
+ if err = newIssueLabels(ctx, issue, toAdd, doer); err != nil {
+ return fmt.Errorf("addLabels: %w", err)
+ }
}
- }
- for _, l := range toRemove {
- if err = deleteIssueLabel(ctx, issue, l, doer); err != nil {
- return fmt.Errorf("removeLabel: %w", err)
+ for _, l := range toRemove {
+ if err = deleteIssueLabel(ctx, issue, l, doer); err != nil {
+ return fmt.Errorf("removeLabel: %w", err)
+ }
}
- }
-
- issue.Labels = nil
- if err = issue.LoadLabels(ctx); err != nil {
- return err
- }
- return committer.Commit()
+ issue.Labels = nil
+ return issue.LoadLabels(ctx)
+ })
}
diff --git a/models/issues/issue_lock.go b/models/issues/issue_lock.go
index fa0d128f74..2e5bf64cc6 100644
--- a/models/issues/issue_lock.go
+++ b/models/issues/issue_lock.go
@@ -47,26 +47,19 @@ func updateIssueLock(ctx context.Context, opts *IssueLockOptions, lock bool) err
commentType = CommentTypeUnlock
}
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- if err := UpdateIssueCols(ctx, opts.Issue, "is_locked"); err != nil {
- return err
- }
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ if err := UpdateIssueCols(ctx, opts.Issue, "is_locked"); err != nil {
+ return err
+ }
- opt := &CreateCommentOptions{
- Doer: opts.Doer,
- Issue: opts.Issue,
- Repo: opts.Issue.Repo,
- Type: commentType,
- Content: opts.Reason,
- }
- if _, err := CreateComment(ctx, opt); err != nil {
+ opt := &CreateCommentOptions{
+ Doer: opts.Doer,
+ Issue: opts.Issue,
+ Repo: opts.Issue.Repo,
+ Type: commentType,
+ Content: opts.Reason,
+ }
+ _, err := CreateComment(ctx, opt)
return err
- }
-
- return committer.Commit()
+ })
}
diff --git a/models/issues/issue_update.go b/models/issues/issue_update.go
index 9b99787e3b..1c16817491 100644
--- a/models/issues/issue_update.go
+++ b/models/issues/issue_update.go
@@ -167,20 +167,9 @@ func CloseIssue(ctx context.Context, issue *Issue, doer *user_model.User) (*Comm
return nil, err
}
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return nil, err
- }
- defer committer.Close()
-
- comment, err := SetIssueAsClosed(ctx, issue, doer, false)
- if err != nil {
- return nil, err
- }
- if err := committer.Commit(); err != nil {
- return nil, err
- }
- return comment, nil
+ return db.WithTx2(ctx, func(ctx context.Context) (*Comment, error) {
+ return SetIssueAsClosed(ctx, issue, doer, false)
+ })
}
// ReopenIssue changes issue status to open.
@@ -192,88 +181,64 @@ func ReopenIssue(ctx context.Context, issue *Issue, doer *user_model.User) (*Com
return nil, err
}
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return nil, err
- }
- defer committer.Close()
-
- comment, err := setIssueAsReopen(ctx, issue, doer)
- if err != nil {
- return nil, err
- }
- if err := committer.Commit(); err != nil {
- return nil, err
- }
- return comment, nil
+ return db.WithTx2(ctx, func(ctx context.Context) (*Comment, error) {
+ return setIssueAsReopen(ctx, issue, doer)
+ })
}
// ChangeIssueTitle changes the title of this issue, as the given user.
func ChangeIssueTitle(ctx context.Context, issue *Issue, doer *user_model.User, oldTitle string) (err error) {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- issue.Title = util.EllipsisDisplayString(issue.Title, 255)
- if err = UpdateIssueCols(ctx, issue, "name"); err != nil {
- return fmt.Errorf("updateIssueCols: %w", err)
- }
-
- if err = issue.LoadRepo(ctx); err != nil {
- return fmt.Errorf("loadRepo: %w", err)
- }
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ issue.Title = util.EllipsisDisplayString(issue.Title, 255)
+ if err = UpdateIssueCols(ctx, issue, "name"); err != nil {
+ return fmt.Errorf("updateIssueCols: %w", err)
+ }
- opts := &CreateCommentOptions{
- Type: CommentTypeChangeTitle,
- Doer: doer,
- Repo: issue.Repo,
- Issue: issue,
- OldTitle: oldTitle,
- NewTitle: issue.Title,
- }
- if _, err = CreateComment(ctx, opts); err != nil {
- return fmt.Errorf("createComment: %w", err)
- }
- if err = issue.AddCrossReferences(ctx, doer, true); err != nil {
- return err
- }
+ if err = issue.LoadRepo(ctx); err != nil {
+ return fmt.Errorf("loadRepo: %w", err)
+ }
- return committer.Commit()
+ opts := &CreateCommentOptions{
+ Type: CommentTypeChangeTitle,
+ Doer: doer,
+ Repo: issue.Repo,
+ Issue: issue,
+ OldTitle: oldTitle,
+ NewTitle: issue.Title,
+ }
+ if _, err = CreateComment(ctx, opts); err != nil {
+ return fmt.Errorf("createComment: %w", err)
+ }
+ return issue.AddCrossReferences(ctx, doer, true)
+ })
}
// ChangeIssueRef changes the branch of this issue, as the given user.
func ChangeIssueRef(ctx context.Context, issue *Issue, doer *user_model.User, oldRef string) (err error) {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- if err = UpdateIssueCols(ctx, issue, "ref"); err != nil {
- return fmt.Errorf("updateIssueCols: %w", err)
- }
-
- if err = issue.LoadRepo(ctx); err != nil {
- return fmt.Errorf("loadRepo: %w", err)
- }
- oldRefFriendly := strings.TrimPrefix(oldRef, git.BranchPrefix)
- newRefFriendly := strings.TrimPrefix(issue.Ref, git.BranchPrefix)
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ if err = UpdateIssueCols(ctx, issue, "ref"); err != nil {
+ return fmt.Errorf("updateIssueCols: %w", err)
+ }
- opts := &CreateCommentOptions{
- Type: CommentTypeChangeIssueRef,
- Doer: doer,
- Repo: issue.Repo,
- Issue: issue,
- OldRef: oldRefFriendly,
- NewRef: newRefFriendly,
- }
- if _, err = CreateComment(ctx, opts); err != nil {
- return fmt.Errorf("createComment: %w", err)
- }
+ if err = issue.LoadRepo(ctx); err != nil {
+ return fmt.Errorf("loadRepo: %w", err)
+ }
+ oldRefFriendly := strings.TrimPrefix(oldRef, git.BranchPrefix)
+ newRefFriendly := strings.TrimPrefix(issue.Ref, git.BranchPrefix)
- return committer.Commit()
+ opts := &CreateCommentOptions{
+ Type: CommentTypeChangeIssueRef,
+ Doer: doer,
+ Repo: issue.Repo,
+ Issue: issue,
+ OldRef: oldRefFriendly,
+ NewRef: newRefFriendly,
+ }
+ if _, err = CreateComment(ctx, opts); err != nil {
+ return fmt.Errorf("createComment: %w", err)
+ }
+ return nil
+ })
}
// AddDeletePRBranchComment adds delete branch comment for pull request issue
@@ -295,64 +260,56 @@ func AddDeletePRBranchComment(ctx context.Context, doer *user_model.User, repo *
// UpdateIssueAttachments update attachments by UUIDs for the issue
func UpdateIssueAttachments(ctx context.Context, issueID int64, uuids []string) (err error) {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
- attachments, err := repo_model.GetAttachmentsByUUIDs(ctx, uuids)
- if err != nil {
- return fmt.Errorf("getAttachmentsByUUIDs [uuids: %v]: %w", uuids, err)
- }
- for i := range attachments {
- attachments[i].IssueID = issueID
- if err := repo_model.UpdateAttachment(ctx, attachments[i]); err != nil {
- return fmt.Errorf("update attachment [id: %d]: %w", attachments[i].ID, err)
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ attachments, err := repo_model.GetAttachmentsByUUIDs(ctx, uuids)
+ if err != nil {
+ return fmt.Errorf("getAttachmentsByUUIDs [uuids: %v]: %w", uuids, err)
}
- }
- return committer.Commit()
+ for i := range attachments {
+ attachments[i].IssueID = issueID
+ if err := repo_model.UpdateAttachment(ctx, attachments[i]); err != nil {
+ return fmt.Errorf("update attachment [id: %d]: %w", attachments[i].ID, err)
+ }
+ }
+ return nil
+ })
}
// ChangeIssueContent changes issue content, as the given user.
func ChangeIssueContent(ctx context.Context, issue *Issue, doer *user_model.User, content string, contentVersion int) (err error) {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- hasContentHistory, err := HasIssueContentHistory(ctx, issue.ID, 0)
- if err != nil {
- return fmt.Errorf("HasIssueContentHistory: %w", err)
- }
- if !hasContentHistory {
- if err = SaveIssueContentHistory(ctx, issue.PosterID, issue.ID, 0,
- issue.CreatedUnix, issue.Content, true); err != nil {
- return fmt.Errorf("SaveIssueContentHistory: %w", err)
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ hasContentHistory, err := HasIssueContentHistory(ctx, issue.ID, 0)
+ if err != nil {
+ return fmt.Errorf("HasIssueContentHistory: %w", err)
+ }
+ if !hasContentHistory {
+ if err = SaveIssueContentHistory(ctx, issue.PosterID, issue.ID, 0,
+ issue.CreatedUnix, issue.Content, true); err != nil {
+ return fmt.Errorf("SaveIssueContentHistory: %w", err)
+ }
}
- }
-
- issue.Content = content
- issue.ContentVersion = contentVersion + 1
- affected, err := db.GetEngine(ctx).ID(issue.ID).Cols("content", "content_version").Where("content_version = ?", contentVersion).Update(issue)
- if err != nil {
- return err
- }
- if affected == 0 {
- return ErrIssueAlreadyChanged
- }
+ issue.Content = content
+ issue.ContentVersion = contentVersion + 1
- if err = SaveIssueContentHistory(ctx, doer.ID, issue.ID, 0,
- timeutil.TimeStampNow(), issue.Content, false); err != nil {
- return fmt.Errorf("SaveIssueContentHistory: %w", err)
- }
+ affected, err := db.GetEngine(ctx).ID(issue.ID).Cols("content", "content_version").Where("content_version = ?", contentVersion).Update(issue)
+ if err != nil {
+ return err
+ }
+ if affected == 0 {
+ return ErrIssueAlreadyChanged
+ }
- if err = issue.AddCrossReferences(ctx, doer, true); err != nil {
- return fmt.Errorf("addCrossReferences: %w", err)
- }
+ if err = SaveIssueContentHistory(ctx, doer.ID, issue.ID, 0,
+ timeutil.TimeStampNow(), issue.Content, false); err != nil {
+ return fmt.Errorf("SaveIssueContentHistory: %w", err)
+ }
- return committer.Commit()
+ if err = issue.AddCrossReferences(ctx, doer, true); err != nil {
+ return fmt.Errorf("addCrossReferences: %w", err)
+ }
+ return nil
+ })
}
// NewIssueOptions represents the options of a new issue.
@@ -512,23 +469,19 @@ func UpdateIssueDeadline(ctx context.Context, issue *Issue, deadlineUnix timeuti
if issue.DeadlineUnix == deadlineUnix {
return nil
}
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
- // Update the deadline
- if err = UpdateIssueCols(ctx, &Issue{ID: issue.ID, DeadlineUnix: deadlineUnix}, "deadline_unix"); err != nil {
- return err
- }
-
- // Make the comment
- if _, err = createDeadlineComment(ctx, doer, issue, deadlineUnix); err != nil {
- return fmt.Errorf("createRemovedDueDateComment: %w", err)
- }
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ // Update the deadline
+ if err = UpdateIssueCols(ctx, &Issue{ID: issue.ID, DeadlineUnix: deadlineUnix}, "deadline_unix"); err != nil {
+ return err
+ }
- return committer.Commit()
+ // Make the comment
+ if _, err = createDeadlineComment(ctx, doer, issue, deadlineUnix); err != nil {
+ return fmt.Errorf("createRemovedDueDateComment: %w", err)
+ }
+ return nil
+ })
}
// FindAndUpdateIssueMentions finds users mentioned in the given content string, and saves them in the database.
diff --git a/models/issues/label.go b/models/issues/label.go
index cfbe100926..25d6f1303e 100644
--- a/models/issues/label.go
+++ b/models/issues/label.go
@@ -209,24 +209,20 @@ func NewLabel(ctx context.Context, l *Label) error {
// NewLabels creates new labels
func NewLabels(ctx context.Context, labels ...*Label) error {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- for _, l := range labels {
- color, err := label.NormalizeColor(l.Color)
- if err != nil {
- return err
- }
- l.Color = color
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ for _, l := range labels {
+ color, err := label.NormalizeColor(l.Color)
+ if err != nil {
+ return err
+ }
+ l.Color = color
- if err := db.Insert(ctx, l); err != nil {
- return err
+ if err := db.Insert(ctx, l); err != nil {
+ return err
+ }
}
- }
- return committer.Commit()
+ return nil
+ })
}
// UpdateLabel updates label information.
@@ -250,35 +246,26 @@ func DeleteLabel(ctx context.Context, id, labelID int64) error {
return err
}
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- sess := db.GetEngine(ctx)
-
- if l.BelongsToOrg() && l.OrgID != id {
- return nil
- }
- if l.BelongsToRepo() && l.RepoID != id {
- return nil
- }
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ if l.BelongsToOrg() && l.OrgID != id {
+ return nil
+ }
+ if l.BelongsToRepo() && l.RepoID != id {
+ return nil
+ }
- if _, err = db.DeleteByID[Label](ctx, labelID); err != nil {
- return err
- } else if _, err = sess.
- Where("label_id = ?", labelID).
- Delete(new(IssueLabel)); err != nil {
- return err
- }
+ if _, err = db.DeleteByID[Label](ctx, labelID); err != nil {
+ return err
+ } else if _, err = db.GetEngine(ctx).
+ Where("label_id = ?", labelID).
+ Delete(new(IssueLabel)); err != nil {
+ return err
+ }
- // delete comments about now deleted label_id
- if _, err = sess.Where("label_id = ?", labelID).Cols("label_id").Delete(&Comment{}); err != nil {
+ // delete comments about now deleted label_id
+ _, err = db.GetEngine(ctx).Where("label_id = ?", labelID).Cols("label_id").Delete(&Comment{})
return err
- }
-
- return committer.Commit()
+ })
}
// GetLabelByID returns a label by given ID.
diff --git a/models/issues/milestone.go b/models/issues/milestone.go
index 4c9bae58f7..373f39f4ff 100644
--- a/models/issues/milestone.go
+++ b/models/issues/milestone.go
@@ -105,22 +105,16 @@ func (m *Milestone) State() api.StateType {
// NewMilestone creates new milestone of repository.
func NewMilestone(ctx context.Context, m *Milestone) (err error) {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ m.Name = strings.TrimSpace(m.Name)
- m.Name = strings.TrimSpace(m.Name)
-
- if err = db.Insert(ctx, m); err != nil {
- return err
- }
+ if err = db.Insert(ctx, m); err != nil {
+ return err
+ }
- if _, err = db.Exec(ctx, "UPDATE `repository` SET num_milestones = num_milestones + 1 WHERE id = ?", m.RepoID); err != nil {
+ _, err = db.Exec(ctx, "UPDATE `repository` SET num_milestones = num_milestones + 1 WHERE id = ?", m.RepoID)
return err
- }
- return committer.Commit()
+ })
}
// HasMilestoneByRepoID returns if the milestone exists in the repository.
@@ -155,28 +149,23 @@ func GetMilestoneByRepoIDANDName(ctx context.Context, repoID int64, name string)
// UpdateMilestone updates information of given milestone.
func UpdateMilestone(ctx context.Context, m *Milestone, oldIsClosed bool) error {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- if m.IsClosed && !oldIsClosed {
- m.ClosedDateUnix = timeutil.TimeStampNow()
- }
-
- if err := updateMilestone(ctx, m); err != nil {
- return err
- }
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ if m.IsClosed && !oldIsClosed {
+ m.ClosedDateUnix = timeutil.TimeStampNow()
+ }
- // if IsClosed changed, update milestone numbers of repository
- if oldIsClosed != m.IsClosed {
- if err := updateRepoMilestoneNum(ctx, m.RepoID); err != nil {
+ if err := updateMilestone(ctx, m); err != nil {
return err
}
- }
- return committer.Commit()
+ // if IsClosed changed, update milestone numbers of repository
+ if oldIsClosed != m.IsClosed {
+ if err := updateRepoMilestoneNum(ctx, m.RepoID); err != nil {
+ return err
+ }
+ }
+ return nil
+ })
}
func updateMilestone(ctx context.Context, m *Milestone) error {
@@ -213,44 +202,28 @@ func UpdateMilestoneCounters(ctx context.Context, id int64) error {
// ChangeMilestoneStatusByRepoIDAndID changes a milestone open/closed status if the milestone ID is in the repo.
func ChangeMilestoneStatusByRepoIDAndID(ctx context.Context, repoID, milestoneID int64, isClosed bool) error {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- m := &Milestone{
- ID: milestoneID,
- RepoID: repoID,
- }
-
- has, err := db.GetEngine(ctx).ID(milestoneID).Where("repo_id = ?", repoID).Get(m)
- if err != nil {
- return err
- } else if !has {
- return ErrMilestoneNotExist{ID: milestoneID, RepoID: repoID}
- }
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ m := &Milestone{
+ ID: milestoneID,
+ RepoID: repoID,
+ }
- if err := changeMilestoneStatus(ctx, m, isClosed); err != nil {
- return err
- }
+ has, err := db.GetEngine(ctx).ID(milestoneID).Where("repo_id = ?", repoID).Get(m)
+ if err != nil {
+ return err
+ } else if !has {
+ return ErrMilestoneNotExist{ID: milestoneID, RepoID: repoID}
+ }
- return committer.Commit()
+ return changeMilestoneStatus(ctx, m, isClosed)
+ })
}
// ChangeMilestoneStatus changes the milestone open/closed status.
func ChangeMilestoneStatus(ctx context.Context, m *Milestone, isClosed bool) (err error) {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- if err := changeMilestoneStatus(ctx, m, isClosed); err != nil {
- return err
- }
-
- return committer.Commit()
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ return changeMilestoneStatus(ctx, m, isClosed)
+ })
}
func changeMilestoneStatus(ctx context.Context, m *Milestone, isClosed bool) error {
@@ -284,40 +257,34 @@ func DeleteMilestoneByRepoID(ctx context.Context, repoID, id int64) error {
return err
}
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- if _, err = db.DeleteByID[Milestone](ctx, m.ID); err != nil {
- return err
- }
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ if _, err = db.DeleteByID[Milestone](ctx, m.ID); err != nil {
+ return err
+ }
- numMilestones, err := db.Count[Milestone](ctx, FindMilestoneOptions{
- RepoID: repo.ID,
- })
- if err != nil {
- return err
- }
- numClosedMilestones, err := db.Count[Milestone](ctx, FindMilestoneOptions{
- RepoID: repo.ID,
- IsClosed: optional.Some(true),
- })
- if err != nil {
- return err
- }
- repo.NumMilestones = int(numMilestones)
- repo.NumClosedMilestones = int(numClosedMilestones)
+ numMilestones, err := db.Count[Milestone](ctx, FindMilestoneOptions{
+ RepoID: repo.ID,
+ })
+ if err != nil {
+ return err
+ }
+ numClosedMilestones, err := db.Count[Milestone](ctx, FindMilestoneOptions{
+ RepoID: repo.ID,
+ IsClosed: optional.Some(true),
+ })
+ if err != nil {
+ return err
+ }
+ repo.NumMilestones = int(numMilestones)
+ repo.NumClosedMilestones = int(numClosedMilestones)
- if _, err = db.GetEngine(ctx).ID(repo.ID).Cols("num_milestones, num_closed_milestones").Update(repo); err != nil {
- return err
- }
+ if _, err = db.GetEngine(ctx).ID(repo.ID).Cols("num_milestones, num_closed_milestones").Update(repo); err != nil {
+ return err
+ }
- if _, err = db.Exec(ctx, "UPDATE `issue` SET milestone_id = 0 WHERE milestone_id = ?", m.ID); err != nil {
+ _, err = db.Exec(ctx, "UPDATE `issue` SET milestone_id = 0 WHERE milestone_id = ?", m.ID)
return err
- }
- return committer.Commit()
+ })
}
func updateRepoMilestoneNum(ctx context.Context, repoID int64) error {
@@ -360,22 +327,15 @@ func InsertMilestones(ctx context.Context, ms ...*Milestone) (err error) {
return nil
}
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
- sess := db.GetEngine(ctx)
-
- // to return the id, so we should not use batch insert
- for _, m := range ms {
- if _, err = sess.NoAutoTime().Insert(m); err != nil {
- return err
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ // to return the id, so we should not use batch insert
+ for _, m := range ms {
+ if _, err = db.GetEngine(ctx).NoAutoTime().Insert(m); err != nil {
+ return err
+ }
}
- }
- if _, err = db.Exec(ctx, "UPDATE `repository` SET num_milestones = num_milestones + ? WHERE id = ?", len(ms), ms[0].RepoID); err != nil {
+ _, err = db.Exec(ctx, "UPDATE `repository` SET num_milestones = num_milestones + ? WHERE id = ?", len(ms), ms[0].RepoID)
return err
- }
- return committer.Commit()
+ })
}
diff --git a/models/issues/pull.go b/models/issues/pull.go
index 4c25b6f0c8..00d7bfe1ca 100644
--- a/models/issues/pull.go
+++ b/models/issues/pull.go
@@ -364,17 +364,10 @@ func (pr *PullRequest) GetApprovers(ctx context.Context) string {
func (pr *PullRequest) getReviewedByLines(ctx context.Context, writer io.Writer) error {
maxReviewers := setting.Repository.PullRequest.DefaultMergeMessageMaxApprovers
-
if maxReviewers == 0 {
return nil
}
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
// Note: This doesn't page as we only expect a very limited number of reviews
reviews, err := FindLatestReviews(ctx, FindReviewOptions{
Types: []ReviewType{ReviewTypeApprove},
@@ -410,7 +403,7 @@ func (pr *PullRequest) getReviewedByLines(ctx context.Context, writer io.Writer)
}
reviewersWritten++
}
- return committer.Commit()
+ return nil
}
// GetGitHeadRefName returns git ref for hidden pull request branch
@@ -464,45 +457,36 @@ func (pr *PullRequest) IsFromFork() bool {
// NewPullRequest creates new pull request with labels for repository.
func NewPullRequest(ctx context.Context, repo *repo_model.Repository, issue *Issue, labelIDs []int64, uuids []string, pr *PullRequest) (err error) {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- idx, err := db.GetNextResourceIndex(ctx, "issue_index", repo.ID)
- if err != nil {
- return fmt.Errorf("generate pull request index failed: %w", err)
- }
-
- issue.Index = idx
- issue.Title = util.EllipsisDisplayString(issue.Title, 255)
-
- if err = NewIssueWithIndex(ctx, issue.Poster, NewIssueOptions{
- Repo: repo,
- Issue: issue,
- LabelIDs: labelIDs,
- Attachments: uuids,
- IsPull: true,
- }); err != nil {
- if repo_model.IsErrUserDoesNotHaveAccessToRepo(err) || IsErrNewIssueInsert(err) {
- return err
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ idx, err := db.GetNextResourceIndex(ctx, "issue_index", repo.ID)
+ if err != nil {
+ return fmt.Errorf("generate pull request index failed: %w", err)
}
- return fmt.Errorf("newIssue: %w", err)
- }
-
- pr.Index = issue.Index
- pr.BaseRepo = repo
- pr.IssueID = issue.ID
- if err = db.Insert(ctx, pr); err != nil {
- return fmt.Errorf("insert pull repo: %w", err)
- }
- if err = committer.Commit(); err != nil {
- return fmt.Errorf("Commit: %w", err)
- }
+ issue.Index = idx
+ issue.Title = util.EllipsisDisplayString(issue.Title, 255)
+
+ if err = NewIssueWithIndex(ctx, issue.Poster, NewIssueOptions{
+ Repo: repo,
+ Issue: issue,
+ LabelIDs: labelIDs,
+ Attachments: uuids,
+ IsPull: true,
+ }); err != nil {
+ if repo_model.IsErrUserDoesNotHaveAccessToRepo(err) || IsErrNewIssueInsert(err) {
+ return err
+ }
+ return fmt.Errorf("newIssue: %w", err)
+ }
- return nil
+ pr.Index = issue.Index
+ pr.BaseRepo = repo
+ pr.IssueID = issue.ID
+ if err = db.Insert(ctx, pr); err != nil {
+ return fmt.Errorf("insert pull repo: %w", err)
+ }
+ return nil
+ })
}
// ErrUserMustCollaborator represents an error that the user must be a collaborator to a given repo.
@@ -977,22 +961,18 @@ func TokenizeCodeOwnersLine(line string) []string {
// InsertPullRequests inserted pull requests
func InsertPullRequests(ctx context.Context, prs ...*PullRequest) error {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
- sess := db.GetEngine(ctx)
- for _, pr := range prs {
- if err := insertIssue(ctx, pr.Issue); err != nil {
- return err
- }
- pr.IssueID = pr.Issue.ID
- if _, err := sess.NoAutoTime().Insert(pr); err != nil {
- return err
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ for _, pr := range prs {
+ if err := insertIssue(ctx, pr.Issue); err != nil {
+ return err
+ }
+ pr.IssueID = pr.Issue.ID
+ if _, err := db.GetEngine(ctx).NoAutoTime().Insert(pr); err != nil {
+ return err
+ }
}
- }
- return committer.Commit()
+ return nil
+ })
}
// GetPullRequestByMergedCommit returns a merged pull request by the given commit
diff --git a/models/issues/reaction.go b/models/issues/reaction.go
index f24001fd23..3b5ad6d7ab 100644
--- a/models/issues/reaction.go
+++ b/models/issues/reaction.go
@@ -224,21 +224,9 @@ func CreateReaction(ctx context.Context, opts *ReactionOptions) (*Reaction, erro
return nil, ErrForbiddenIssueReaction{opts.Type}
}
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return nil, err
- }
- defer committer.Close()
-
- reaction, err := createReaction(ctx, opts)
- if err != nil {
- return reaction, err
- }
-
- if err := committer.Commit(); err != nil {
- return nil, err
- }
- return reaction, nil
+ return db.WithTx2(ctx, func(ctx context.Context) (*Reaction, error) {
+ return createReaction(ctx, opts)
+ })
}
// DeleteReaction deletes reaction for issue or comment.
diff --git a/models/issues/review.go b/models/issues/review.go
index 71fdb7456f..b758fa5ffa 100644
--- a/models/issues/review.go
+++ b/models/issues/review.go
@@ -334,54 +334,51 @@ func IsOfficialReviewerTeam(ctx context.Context, issue *Issue, team *organizatio
// CreateReview creates a new review based on opts
func CreateReview(ctx context.Context, opts CreateReviewOptions) (*Review, error) {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return nil, err
- }
- defer committer.Close()
- sess := db.GetEngine(ctx)
-
- review := &Review{
- Issue: opts.Issue,
- IssueID: opts.Issue.ID,
- Reviewer: opts.Reviewer,
- ReviewerTeam: opts.ReviewerTeam,
- Content: opts.Content,
- Official: opts.Official,
- CommitID: opts.CommitID,
- Stale: opts.Stale,
- }
+ return db.WithTx2(ctx, func(ctx context.Context) (*Review, error) {
+ sess := db.GetEngine(ctx)
+
+ review := &Review{
+ Issue: opts.Issue,
+ IssueID: opts.Issue.ID,
+ Reviewer: opts.Reviewer,
+ ReviewerTeam: opts.ReviewerTeam,
+ Content: opts.Content,
+ Official: opts.Official,
+ CommitID: opts.CommitID,
+ Stale: opts.Stale,
+ }
- if opts.Reviewer != nil {
- review.Type = opts.Type
- review.ReviewerID = opts.Reviewer.ID
+ if opts.Reviewer != nil {
+ review.Type = opts.Type
+ review.ReviewerID = opts.Reviewer.ID
- reviewCond := builder.Eq{"reviewer_id": opts.Reviewer.ID, "issue_id": opts.Issue.ID}
- // make sure user review requests are cleared
- if opts.Type != ReviewTypePending {
- if _, err := sess.Where(reviewCond.And(builder.Eq{"type": ReviewTypeRequest})).Delete(new(Review)); err != nil {
- return nil, err
+ reviewCond := builder.Eq{"reviewer_id": opts.Reviewer.ID, "issue_id": opts.Issue.ID}
+ // make sure user review requests are cleared
+ if opts.Type != ReviewTypePending {
+ if _, err := sess.Where(reviewCond.And(builder.Eq{"type": ReviewTypeRequest})).Delete(new(Review)); err != nil {
+ return nil, err
+ }
}
- }
- // make sure if the created review gets dismissed no old review surface
- // other types can be ignored, as they don't affect branch protection
- if opts.Type == ReviewTypeApprove || opts.Type == ReviewTypeReject {
- if _, err := sess.Where(reviewCond.And(builder.In("type", ReviewTypeApprove, ReviewTypeReject))).
- Cols("dismissed").Update(&Review{Dismissed: true}); err != nil {
- return nil, err
+ // make sure if the created review gets dismissed no old review surface
+ // other types can be ignored, as they don't affect branch protection
+ if opts.Type == ReviewTypeApprove || opts.Type == ReviewTypeReject {
+ if _, err := sess.Where(reviewCond.And(builder.In("type", ReviewTypeApprove, ReviewTypeReject))).
+ Cols("dismissed").Update(&Review{Dismissed: true}); err != nil {
+ return nil, err
+ }
}
+ } else if opts.ReviewerTeam != nil {
+ review.Type = ReviewTypeRequest
+ review.ReviewerTeamID = opts.ReviewerTeam.ID
+ } else {
+ return nil, errors.New("provide either reviewer or reviewer team")
}
- } else if opts.ReviewerTeam != nil {
- review.Type = ReviewTypeRequest
- review.ReviewerTeamID = opts.ReviewerTeam.ID
- } else {
- return nil, errors.New("provide either reviewer or reviewer team")
- }
- if _, err := sess.Insert(review); err != nil {
- return nil, err
- }
- return review, committer.Commit()
+ if _, err := sess.Insert(review); err != nil {
+ return nil, err
+ }
+ return review, nil
+ })
}
// GetCurrentReview returns the current pending review of reviewer for given issue
@@ -605,168 +602,152 @@ func DismissReview(ctx context.Context, review *Review, isDismiss bool) (err err
// InsertReviews inserts review and review comments
func InsertReviews(ctx context.Context, reviews []*Review) error {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
- sess := db.GetEngine(ctx)
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ sess := db.GetEngine(ctx)
- for _, review := range reviews {
- if _, err := sess.NoAutoTime().Insert(review); err != nil {
- return err
- }
+ for _, review := range reviews {
+ if _, err := sess.NoAutoTime().Insert(review); err != nil {
+ return err
+ }
- if _, err := sess.NoAutoTime().Insert(&Comment{
- Type: CommentTypeReview,
- Content: review.Content,
- PosterID: review.ReviewerID,
- OriginalAuthor: review.OriginalAuthor,
- OriginalAuthorID: review.OriginalAuthorID,
- IssueID: review.IssueID,
- ReviewID: review.ID,
- CreatedUnix: review.CreatedUnix,
- UpdatedUnix: review.UpdatedUnix,
- }); err != nil {
- return err
- }
+ if _, err := sess.NoAutoTime().Insert(&Comment{
+ Type: CommentTypeReview,
+ Content: review.Content,
+ PosterID: review.ReviewerID,
+ OriginalAuthor: review.OriginalAuthor,
+ OriginalAuthorID: review.OriginalAuthorID,
+ IssueID: review.IssueID,
+ ReviewID: review.ID,
+ CreatedUnix: review.CreatedUnix,
+ UpdatedUnix: review.UpdatedUnix,
+ }); err != nil {
+ return err
+ }
- for _, c := range review.Comments {
- c.ReviewID = review.ID
- }
+ for _, c := range review.Comments {
+ c.ReviewID = review.ID
+ }
- if len(review.Comments) > 0 {
- if _, err := sess.NoAutoTime().Insert(review.Comments); err != nil {
- return err
+ if len(review.Comments) > 0 {
+ if _, err := sess.NoAutoTime().Insert(review.Comments); err != nil {
+ return err
+ }
}
- }
- if err := UpdateIssueNumComments(ctx, review.IssueID); err != nil {
- return err
+ if err := UpdateIssueNumComments(ctx, review.IssueID); err != nil {
+ return err
+ }
}
- }
-
- return committer.Commit()
+ return nil
+ })
}
// AddReviewRequest add a review request from one reviewer
func AddReviewRequest(ctx context.Context, issue *Issue, reviewer, doer *user_model.User) (*Comment, error) {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return nil, err
- }
- defer committer.Close()
- sess := db.GetEngine(ctx)
+ return db.WithTx2(ctx, func(ctx context.Context) (*Comment, error) {
+ sess := db.GetEngine(ctx)
- review, err := GetReviewByIssueIDAndUserID(ctx, issue.ID, reviewer.ID)
- if err != nil && !IsErrReviewNotExist(err) {
- return nil, err
- }
-
- if review != nil {
- // skip it when reviewer has been request to review
- if review.Type == ReviewTypeRequest {
- return nil, committer.Commit() // still commit the transaction, or committer.Close() will rollback it, even if it's a reused transaction.
- }
-
- if issue.IsClosed {
- return nil, ErrReviewRequestOnClosedPR{}
+ review, err := GetReviewByIssueIDAndUserID(ctx, issue.ID, reviewer.ID)
+ if err != nil && !IsErrReviewNotExist(err) {
+ return nil, err
}
- if issue.IsPull {
- if err := issue.LoadPullRequest(ctx); err != nil {
- return nil, err
+ if review != nil {
+ // skip it when reviewer has been request to review
+ if review.Type == ReviewTypeRequest {
+ return nil, nil // still commit the transaction, or committer.Close() will rollback it, even if it's a reused transaction.
}
- if issue.PullRequest.HasMerged {
+
+ if issue.IsClosed {
return nil, ErrReviewRequestOnClosedPR{}
}
+
+ if issue.IsPull {
+ if err := issue.LoadPullRequest(ctx); err != nil {
+ return nil, err
+ }
+ if issue.PullRequest.HasMerged {
+ return nil, ErrReviewRequestOnClosedPR{}
+ }
+ }
}
- }
- // if the reviewer is an official reviewer,
- // remove the official flag in the all previous reviews
- official, err := IsOfficialReviewer(ctx, issue, reviewer)
- if err != nil {
- return nil, err
- } else if official {
- if _, err := sess.Exec("UPDATE `review` SET official=? WHERE issue_id=? AND reviewer_id=?", false, issue.ID, reviewer.ID); err != nil {
+ // if the reviewer is an official reviewer,
+ // remove the official flag in the all previous reviews
+ official, err := IsOfficialReviewer(ctx, issue, reviewer)
+ if err != nil {
return nil, err
+ } else if official {
+ if _, err := sess.Exec("UPDATE `review` SET official=? WHERE issue_id=? AND reviewer_id=?", false, issue.ID, reviewer.ID); err != nil {
+ return nil, err
+ }
}
- }
- review, err = CreateReview(ctx, CreateReviewOptions{
- Type: ReviewTypeRequest,
- Issue: issue,
- Reviewer: reviewer,
- Official: official,
- Stale: false,
- })
- if err != nil {
- return nil, err
- }
+ review, err = CreateReview(ctx, CreateReviewOptions{
+ Type: ReviewTypeRequest,
+ Issue: issue,
+ Reviewer: reviewer,
+ Official: official,
+ Stale: false,
+ })
+ if err != nil {
+ return nil, err
+ }
- comment, err := CreateComment(ctx, &CreateCommentOptions{
- Type: CommentTypeReviewRequest,
- Doer: doer,
- Repo: issue.Repo,
- Issue: issue,
- RemovedAssignee: false, // Use RemovedAssignee as !isRequest
- AssigneeID: reviewer.ID, // Use AssigneeID as reviewer ID
- ReviewID: review.ID,
- })
- if err != nil {
- return nil, err
- }
+ comment, err := CreateComment(ctx, &CreateCommentOptions{
+ Type: CommentTypeReviewRequest,
+ Doer: doer,
+ Repo: issue.Repo,
+ Issue: issue,
+ RemovedAssignee: false, // Use RemovedAssignee as !isRequest
+ AssigneeID: reviewer.ID, // Use AssigneeID as reviewer ID
+ ReviewID: review.ID,
+ })
+ if err != nil {
+ return nil, err
+ }
- // func caller use the created comment to retrieve created review too.
- comment.Review = review
+ // func caller use the created comment to retrieve created review too.
+ comment.Review = review
- return comment, committer.Commit()
+ return comment, nil
+ })
}
// RemoveReviewRequest remove a review request from one reviewer
func RemoveReviewRequest(ctx context.Context, issue *Issue, reviewer, doer *user_model.User) (*Comment, error) {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return nil, err
- }
- defer committer.Close()
-
- review, err := GetReviewByIssueIDAndUserID(ctx, issue.ID, reviewer.ID)
- if err != nil && !IsErrReviewNotExist(err) {
- return nil, err
- }
+ return db.WithTx2(ctx, func(ctx context.Context) (*Comment, error) {
+ review, err := GetReviewByIssueIDAndUserID(ctx, issue.ID, reviewer.ID)
+ if err != nil && !IsErrReviewNotExist(err) {
+ return nil, err
+ }
- if review == nil || review.Type != ReviewTypeRequest {
- return nil, nil
- }
+ if review == nil || review.Type != ReviewTypeRequest {
+ return nil, nil
+ }
- if _, err = db.DeleteByBean(ctx, review); err != nil {
- return nil, err
- }
+ if _, err = db.DeleteByBean(ctx, review); err != nil {
+ return nil, err
+ }
- official, err := IsOfficialReviewer(ctx, issue, reviewer)
- if err != nil {
- return nil, err
- } else if official {
- if err := restoreLatestOfficialReview(ctx, issue.ID, reviewer.ID); err != nil {
+ official, err := IsOfficialReviewer(ctx, issue, reviewer)
+ if err != nil {
return nil, err
+ } else if official {
+ if err := restoreLatestOfficialReview(ctx, issue.ID, reviewer.ID); err != nil {
+ return nil, err
+ }
}
- }
- comment, err := CreateComment(ctx, &CreateCommentOptions{
- Type: CommentTypeReviewRequest,
- Doer: doer,
- Repo: issue.Repo,
- Issue: issue,
- RemovedAssignee: true, // Use RemovedAssignee as !isRequest
- AssigneeID: reviewer.ID, // Use AssigneeID as reviewer ID
+ return CreateComment(ctx, &CreateCommentOptions{
+ Type: CommentTypeReviewRequest,
+ Doer: doer,
+ Repo: issue.Repo,
+ Issue: issue,
+ RemovedAssignee: true, // Use RemovedAssignee as !isRequest
+ AssigneeID: reviewer.ID, // Use AssigneeID as reviewer ID
+ })
})
- if err != nil {
- return nil, err
- }
-
- return comment, committer.Commit()
}
// Recalculate the latest official review for reviewer
@@ -787,120 +768,112 @@ func restoreLatestOfficialReview(ctx context.Context, issueID, reviewerID int64)
// AddTeamReviewRequest add a review request from one team
func AddTeamReviewRequest(ctx context.Context, issue *Issue, reviewer *organization.Team, doer *user_model.User) (*Comment, error) {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return nil, err
- }
- defer committer.Close()
+ return db.WithTx2(ctx, func(ctx context.Context) (*Comment, error) {
+ review, err := GetTeamReviewerByIssueIDAndTeamID(ctx, issue.ID, reviewer.ID)
+ if err != nil && !IsErrReviewNotExist(err) {
+ return nil, err
+ }
- review, err := GetTeamReviewerByIssueIDAndTeamID(ctx, issue.ID, reviewer.ID)
- if err != nil && !IsErrReviewNotExist(err) {
- return nil, err
- }
+ // This team already has been requested to review - therefore skip this.
+ if review != nil {
+ return nil, nil
+ }
- // This team already has been requested to review - therefore skip this.
- if review != nil {
- return nil, nil
- }
+ official, err := IsOfficialReviewerTeam(ctx, issue, reviewer)
+ if err != nil {
+ return nil, fmt.Errorf("isOfficialReviewerTeam(): %w", err)
+ } else if !official {
+ if official, err = IsOfficialReviewer(ctx, issue, doer); err != nil {
+ return nil, fmt.Errorf("isOfficialReviewer(): %w", err)
+ }
+ }
- official, err := IsOfficialReviewerTeam(ctx, issue, reviewer)
- if err != nil {
- return nil, fmt.Errorf("isOfficialReviewerTeam(): %w", err)
- } else if !official {
- if official, err = IsOfficialReviewer(ctx, issue, doer); err != nil {
- return nil, fmt.Errorf("isOfficialReviewer(): %w", err)
+ if review, err = CreateReview(ctx, CreateReviewOptions{
+ Type: ReviewTypeRequest,
+ Issue: issue,
+ ReviewerTeam: reviewer,
+ Official: official,
+ Stale: false,
+ }); err != nil {
+ return nil, err
}
- }
- if review, err = CreateReview(ctx, CreateReviewOptions{
- Type: ReviewTypeRequest,
- Issue: issue,
- ReviewerTeam: reviewer,
- Official: official,
- Stale: false,
- }); err != nil {
- return nil, err
- }
+ if official {
+ if _, err := db.Exec(ctx, "UPDATE `review` SET official=? WHERE issue_id=? AND reviewer_team_id=?", false, issue.ID, reviewer.ID); err != nil {
+ return nil, err
+ }
+ }
- if official {
- if _, err := db.Exec(ctx, "UPDATE `review` SET official=? WHERE issue_id=? AND reviewer_team_id=?", false, issue.ID, reviewer.ID); err != nil {
- return nil, err
+ comment, err := CreateComment(ctx, &CreateCommentOptions{
+ Type: CommentTypeReviewRequest,
+ Doer: doer,
+ Repo: issue.Repo,
+ Issue: issue,
+ RemovedAssignee: false, // Use RemovedAssignee as !isRequest
+ AssigneeTeamID: reviewer.ID, // Use AssigneeTeamID as reviewer team ID
+ ReviewID: review.ID,
+ })
+ if err != nil {
+ return nil, fmt.Errorf("CreateComment(): %w", err)
}
- }
- comment, err := CreateComment(ctx, &CreateCommentOptions{
- Type: CommentTypeReviewRequest,
- Doer: doer,
- Repo: issue.Repo,
- Issue: issue,
- RemovedAssignee: false, // Use RemovedAssignee as !isRequest
- AssigneeTeamID: reviewer.ID, // Use AssigneeTeamID as reviewer team ID
- ReviewID: review.ID,
+ return comment, nil
})
- if err != nil {
- return nil, fmt.Errorf("CreateComment(): %w", err)
- }
-
- return comment, committer.Commit()
}
// RemoveTeamReviewRequest remove a review request from one team
func RemoveTeamReviewRequest(ctx context.Context, issue *Issue, reviewer *organization.Team, doer *user_model.User) (*Comment, error) {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return nil, err
- }
- defer committer.Close()
-
- review, err := GetTeamReviewerByIssueIDAndTeamID(ctx, issue.ID, reviewer.ID)
- if err != nil && !IsErrReviewNotExist(err) {
- return nil, err
- }
-
- if review == nil {
- return nil, nil
- }
-
- if _, err = db.DeleteByBean(ctx, review); err != nil {
- return nil, err
- }
+ return db.WithTx2(ctx, func(ctx context.Context) (*Comment, error) {
+ review, err := GetTeamReviewerByIssueIDAndTeamID(ctx, issue.ID, reviewer.ID)
+ if err != nil && !IsErrReviewNotExist(err) {
+ return nil, err
+ }
- official, err := IsOfficialReviewerTeam(ctx, issue, reviewer)
- if err != nil {
- return nil, fmt.Errorf("isOfficialReviewerTeam(): %w", err)
- }
+ if review == nil {
+ return nil, nil
+ }
- if official {
- // recalculate which is the latest official review from that team
- review, err := GetReviewByIssueIDAndUserID(ctx, issue.ID, -reviewer.ID)
- if err != nil && !IsErrReviewNotExist(err) {
+ if _, err = db.DeleteByBean(ctx, review); err != nil {
return nil, err
}
- if review != nil {
- if _, err := db.Exec(ctx, "UPDATE `review` SET official=? WHERE id=?", true, review.ID); err != nil {
+ official, err := IsOfficialReviewerTeam(ctx, issue, reviewer)
+ if err != nil {
+ return nil, fmt.Errorf("isOfficialReviewerTeam(): %w", err)
+ }
+
+ if official {
+ // recalculate which is the latest official review from that team
+ review, err := GetReviewByIssueIDAndUserID(ctx, issue.ID, -reviewer.ID)
+ if err != nil && !IsErrReviewNotExist(err) {
return nil, err
}
+
+ if review != nil {
+ if _, err := db.Exec(ctx, "UPDATE `review` SET official=? WHERE id=?", true, review.ID); err != nil {
+ return nil, err
+ }
+ }
}
- }
- if doer == nil {
- return nil, committer.Commit()
- }
+ if doer == nil {
+ return nil, nil
+ }
- comment, err := CreateComment(ctx, &CreateCommentOptions{
- Type: CommentTypeReviewRequest,
- Doer: doer,
- Repo: issue.Repo,
- Issue: issue,
- RemovedAssignee: true, // Use RemovedAssignee as !isRequest
- AssigneeTeamID: reviewer.ID, // Use AssigneeTeamID as reviewer team ID
- })
- if err != nil {
- return nil, fmt.Errorf("CreateComment(): %w", err)
- }
+ comment, err := CreateComment(ctx, &CreateCommentOptions{
+ Type: CommentTypeReviewRequest,
+ Doer: doer,
+ Repo: issue.Repo,
+ Issue: issue,
+ RemovedAssignee: true, // Use RemovedAssignee as !isRequest
+ AssigneeTeamID: reviewer.ID, // Use AssigneeTeamID as reviewer team ID
+ })
+ if err != nil {
+ return nil, fmt.Errorf("CreateComment(): %w", err)
+ }
- return comment, committer.Commit()
+ return comment, nil
+ })
}
// MarkConversation Add or remove Conversation mark for a code comment
@@ -966,61 +939,56 @@ func CanMarkConversation(ctx context.Context, issue *Issue, doer *user_model.Use
// DeleteReview delete a review and it's code comments
func DeleteReview(ctx context.Context, r *Review) error {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- if r.ID == 0 {
- return errors.New("review is not allowed to be 0")
- }
-
- if r.Type == ReviewTypeRequest {
- return errors.New("review request can not be deleted using this method")
- }
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ if r.ID == 0 {
+ return errors.New("review is not allowed to be 0")
+ }
- opts := FindCommentsOptions{
- Type: CommentTypeCode,
- IssueID: r.IssueID,
- ReviewID: r.ID,
- }
+ if r.Type == ReviewTypeRequest {
+ return errors.New("review request can not be deleted using this method")
+ }
- if _, err := db.Delete[Comment](ctx, opts); err != nil {
- return err
- }
+ opts := FindCommentsOptions{
+ Type: CommentTypeCode,
+ IssueID: r.IssueID,
+ ReviewID: r.ID,
+ }
- opts = FindCommentsOptions{
- Type: CommentTypeReview,
- IssueID: r.IssueID,
- ReviewID: r.ID,
- }
+ if _, err := db.Delete[Comment](ctx, opts); err != nil {
+ return err
+ }
- if _, err := db.Delete[Comment](ctx, opts); err != nil {
- return err
- }
+ opts = FindCommentsOptions{
+ Type: CommentTypeReview,
+ IssueID: r.IssueID,
+ ReviewID: r.ID,
+ }
- opts = FindCommentsOptions{
- Type: CommentTypeDismissReview,
- IssueID: r.IssueID,
- ReviewID: r.ID,
- }
+ if _, err := db.Delete[Comment](ctx, opts); err != nil {
+ return err
+ }
- if _, err := db.Delete[Comment](ctx, opts); err != nil {
- return err
- }
+ opts = FindCommentsOptions{
+ Type: CommentTypeDismissReview,
+ IssueID: r.IssueID,
+ ReviewID: r.ID,
+ }
- if _, err := db.DeleteByID[Review](ctx, r.ID); err != nil {
- return err
- }
+ if _, err := db.Delete[Comment](ctx, opts); err != nil {
+ return err
+ }
- if r.Official {
- if err := restoreLatestOfficialReview(ctx, r.IssueID, r.ReviewerID); err != nil {
+ if _, err := db.DeleteByID[Review](ctx, r.ID); err != nil {
return err
}
- }
- return committer.Commit()
+ if r.Official {
+ if err := restoreLatestOfficialReview(ctx, r.IssueID, r.ReviewerID); err != nil {
+ return err
+ }
+ }
+ return nil
+ })
}
// GetCodeCommentsCount return count of CodeComments a Review has
diff --git a/models/issues/tracked_time.go b/models/issues/tracked_time.go
index 2afbe272ed..9c11881e44 100644
--- a/models/issues/tracked_time.go
+++ b/models/issues/tracked_time.go
@@ -168,35 +168,31 @@ func GetTrackedSeconds(ctx context.Context, opts FindTrackedTimesOptions) (track
// AddTime will add the given time (in seconds) to the issue
func AddTime(ctx context.Context, user *user_model.User, issue *Issue, amount int64, created time.Time) (*TrackedTime, error) {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return nil, err
- }
- defer committer.Close()
-
- t, err := addTime(ctx, user, issue, amount, created)
- if err != nil {
- return nil, err
- }
+ return db.WithTx2(ctx, func(ctx context.Context) (*TrackedTime, error) {
+ t, err := addTime(ctx, user, issue, amount, created)
+ if err != nil {
+ return nil, err
+ }
- if err := issue.LoadRepo(ctx); err != nil {
- return nil, err
- }
+ if err := issue.LoadRepo(ctx); err != nil {
+ return nil, err
+ }
- if _, err := CreateComment(ctx, &CreateCommentOptions{
- Issue: issue,
- Repo: issue.Repo,
- Doer: user,
- // Content before v1.21 did store the formatted string instead of seconds,
- // so use "|" as delimiter to mark the new format
- Content: fmt.Sprintf("|%d", amount),
- Type: CommentTypeAddTimeManual,
- TimeID: t.ID,
- }); err != nil {
- return nil, err
- }
+ if _, err := CreateComment(ctx, &CreateCommentOptions{
+ Issue: issue,
+ Repo: issue.Repo,
+ Doer: user,
+ // Content before v1.21 did store the formatted string instead of seconds,
+ // so use "|" as delimiter to mark the new format
+ Content: fmt.Sprintf("|%d", amount),
+ Type: CommentTypeAddTimeManual,
+ TimeID: t.ID,
+ }); err != nil {
+ return nil, err
+ }
- return t, committer.Commit()
+ return t, nil
+ })
}
func addTime(ctx context.Context, user *user_model.User, issue *Issue, amount int64, created time.Time) (*TrackedTime, error) {
@@ -241,72 +237,58 @@ func TotalTimesForEachUser(ctx context.Context, options *FindTrackedTimesOptions
// DeleteIssueUserTimes deletes times for issue
func DeleteIssueUserTimes(ctx context.Context, issue *Issue, user *user_model.User) error {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- opts := FindTrackedTimesOptions{
- IssueID: issue.ID,
- UserID: user.ID,
- }
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ opts := FindTrackedTimesOptions{
+ IssueID: issue.ID,
+ UserID: user.ID,
+ }
- removedTime, err := deleteTimes(ctx, opts)
- if err != nil {
- return err
- }
- if removedTime == 0 {
- return db.ErrNotExist{Resource: "tracked_time"}
- }
+ removedTime, err := deleteTimes(ctx, opts)
+ if err != nil {
+ return err
+ }
+ if removedTime == 0 {
+ return db.ErrNotExist{Resource: "tracked_time"}
+ }
- if err := issue.LoadRepo(ctx); err != nil {
- return err
- }
- if _, err := CreateComment(ctx, &CreateCommentOptions{
- Issue: issue,
- Repo: issue.Repo,
- Doer: user,
- // Content before v1.21 did store the formatted string instead of seconds,
- // so use "|" as delimiter to mark the new format
- Content: fmt.Sprintf("|%d", removedTime),
- Type: CommentTypeDeleteTimeManual,
- }); err != nil {
+ if err := issue.LoadRepo(ctx); err != nil {
+ return err
+ }
+ _, err = CreateComment(ctx, &CreateCommentOptions{
+ Issue: issue,
+ Repo: issue.Repo,
+ Doer: user,
+ // Content before v1.21 did store the formatted string instead of seconds,
+ // so use "|" as delimiter to mark the new format
+ Content: fmt.Sprintf("|%d", removedTime),
+ Type: CommentTypeDeleteTimeManual,
+ })
return err
- }
-
- return committer.Commit()
+ })
}
// DeleteTime delete a specific Time
func DeleteTime(ctx context.Context, t *TrackedTime) error {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- if err := t.LoadAttributes(ctx); err != nil {
- return err
- }
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ if err := t.LoadAttributes(ctx); err != nil {
+ return err
+ }
- if err := deleteTime(ctx, t); err != nil {
- return err
- }
+ if err := deleteTime(ctx, t); err != nil {
+ return err
+ }
- if _, err := CreateComment(ctx, &CreateCommentOptions{
- Issue: t.Issue,
- Repo: t.Issue.Repo,
- Doer: t.User,
- // Content before v1.21 did store the formatted string instead of seconds,
- // so use "|" as delimiter to mark the new format
- Content: fmt.Sprintf("|%d", t.Time),
- Type: CommentTypeDeleteTimeManual,
- }); err != nil {
+ _, err := CreateComment(ctx, &CreateCommentOptions{
+ Issue: t.Issue,
+ Repo: t.Issue.Repo,
+ Doer: t.User,
+ // Content before v1.21 did store the formatted string instead of seconds,
+ // so use "|" as delimiter to mark the new format
+ Content: fmt.Sprintf("|%d", t.Time),
+ Type: CommentTypeDeleteTimeManual,
+ })
return err
- }
-
- return committer.Commit()
+ })
}
func deleteTimes(ctx context.Context, opts FindTrackedTimesOptions) (removedTime int64, err error) {
diff --git a/models/organization/org.go b/models/organization/org.go
index 0f3aef146c..5eba004d69 100644
--- a/models/organization/org.go
+++ b/models/organization/org.go
@@ -310,74 +310,69 @@ func CreateOrganization(ctx context.Context, org *Organization, owner *user_mode
org.NumMembers = 1
org.Type = user_model.UserTypeOrganization
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- if err = user_model.DeleteUserRedirect(ctx, org.Name); err != nil {
- return err
- }
-
- if err = db.Insert(ctx, org); err != nil {
- return fmt.Errorf("insert organization: %w", err)
- }
- if err = user_model.GenerateRandomAvatar(ctx, org.AsUser()); err != nil {
- return fmt.Errorf("generate random avatar: %w", err)
- }
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ if err = user_model.DeleteUserRedirect(ctx, org.Name); err != nil {
+ return err
+ }
- // Add initial creator to organization and owner team.
- if err = db.Insert(ctx, &OrgUser{
- UID: owner.ID,
- OrgID: org.ID,
- IsPublic: setting.Service.DefaultOrgMemberVisible,
- }); err != nil {
- return fmt.Errorf("insert org-user relation: %w", err)
- }
+ if err = db.Insert(ctx, org); err != nil {
+ return fmt.Errorf("insert organization: %w", err)
+ }
+ if err = user_model.GenerateRandomAvatar(ctx, org.AsUser()); err != nil {
+ return fmt.Errorf("generate random avatar: %w", err)
+ }
- // Create default owner team.
- t := &Team{
- OrgID: org.ID,
- LowerName: strings.ToLower(OwnerTeamName),
- Name: OwnerTeamName,
- AccessMode: perm.AccessModeOwner,
- NumMembers: 1,
- IncludesAllRepositories: true,
- CanCreateOrgRepo: true,
- }
- if err = db.Insert(ctx, t); err != nil {
- return fmt.Errorf("insert owner team: %w", err)
- }
+ // Add initial creator to organization and owner team.
+ if err = db.Insert(ctx, &OrgUser{
+ UID: owner.ID,
+ OrgID: org.ID,
+ IsPublic: setting.Service.DefaultOrgMemberVisible,
+ }); err != nil {
+ return fmt.Errorf("insert org-user relation: %w", err)
+ }
- // insert units for team
- units := make([]TeamUnit, 0, len(unit.AllRepoUnitTypes))
- for _, tp := range unit.AllRepoUnitTypes {
- up := perm.AccessModeOwner
- if tp == unit.TypeExternalTracker || tp == unit.TypeExternalWiki {
- up = perm.AccessModeRead
+ // Create default owner team.
+ t := &Team{
+ OrgID: org.ID,
+ LowerName: strings.ToLower(OwnerTeamName),
+ Name: OwnerTeamName,
+ AccessMode: perm.AccessModeOwner,
+ NumMembers: 1,
+ IncludesAllRepositories: true,
+ CanCreateOrgRepo: true,
+ }
+ if err = db.Insert(ctx, t); err != nil {
+ return fmt.Errorf("insert owner team: %w", err)
}
- units = append(units, TeamUnit{
- OrgID: org.ID,
- TeamID: t.ID,
- Type: tp,
- AccessMode: up,
- })
- }
- if err = db.Insert(ctx, &units); err != nil {
- return err
- }
+ // insert units for team
+ units := make([]TeamUnit, 0, len(unit.AllRepoUnitTypes))
+ for _, tp := range unit.AllRepoUnitTypes {
+ up := perm.AccessModeOwner
+ if tp == unit.TypeExternalTracker || tp == unit.TypeExternalWiki {
+ up = perm.AccessModeRead
+ }
+ units = append(units, TeamUnit{
+ OrgID: org.ID,
+ TeamID: t.ID,
+ Type: tp,
+ AccessMode: up,
+ })
+ }
- if err = db.Insert(ctx, &TeamUser{
- UID: owner.ID,
- OrgID: org.ID,
- TeamID: t.ID,
- }); err != nil {
- return fmt.Errorf("insert team-user relation: %w", err)
- }
+ if err = db.Insert(ctx, &units); err != nil {
+ return err
+ }
- return committer.Commit()
+ if err = db.Insert(ctx, &TeamUser{
+ UID: owner.ID,
+ OrgID: org.ID,
+ TeamID: t.ID,
+ }); err != nil {
+ return fmt.Errorf("insert team-user relation: %w", err)
+ }
+ return nil
+ })
}
// GetOrgByName returns organization by given name.
@@ -499,31 +494,26 @@ func AddOrgUser(ctx context.Context, orgID, uid int64) error {
return err
}
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- // check in transaction
- isAlreadyMember, err = IsOrganizationMember(ctx, orgID, uid)
- if err != nil || isAlreadyMember {
- return err
- }
-
- ou := &OrgUser{
- UID: uid,
- OrgID: orgID,
- IsPublic: setting.Service.DefaultOrgMemberVisible,
- }
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ // check in transaction
+ isAlreadyMember, err = IsOrganizationMember(ctx, orgID, uid)
+ if err != nil || isAlreadyMember {
+ return err
+ }
- if err := db.Insert(ctx, ou); err != nil {
- return err
- } else if _, err = db.Exec(ctx, "UPDATE `user` SET num_members = num_members + 1 WHERE id = ?", orgID); err != nil {
- return err
- }
+ ou := &OrgUser{
+ UID: uid,
+ OrgID: orgID,
+ IsPublic: setting.Service.DefaultOrgMemberVisible,
+ }
- return committer.Commit()
+ if err := db.Insert(ctx, ou); err != nil {
+ return err
+ } else if _, err = db.Exec(ctx, "UPDATE `user` SET num_members = num_members + 1 WHERE id = ?", orgID); err != nil {
+ return err
+ }
+ return nil
+ })
}
// GetOrgByID returns the user object by given ID if exists.
diff --git a/models/organization/team_unit.go b/models/organization/team_unit.go
index 3087b70770..c6ec6b39b2 100644
--- a/models/organization/team_unit.go
+++ b/models/organization/team_unit.go
@@ -31,21 +31,16 @@ func getUnitsByTeamID(ctx context.Context, teamID int64) (units []*TeamUnit, err
// UpdateTeamUnits updates a teams's units
func UpdateTeamUnits(ctx context.Context, team *Team, units []TeamUnit) (err error) {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- if _, err = db.GetEngine(ctx).Where("team_id = ?", team.ID).Delete(new(TeamUnit)); err != nil {
- return err
- }
-
- if len(units) > 0 {
- if err = db.Insert(ctx, units); err != nil {
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ if _, err = db.GetEngine(ctx).Where("team_id = ?", team.ID).Delete(new(TeamUnit)); err != nil {
return err
}
- }
- return committer.Commit()
+ if len(units) > 0 {
+ if err = db.Insert(ctx, units); err != nil {
+ return err
+ }
+ }
+ return nil
+ })
}
diff --git a/models/project/project.go b/models/project/project.go
index f516466854..c003664fa3 100644
--- a/models/project/project.go
+++ b/models/project/project.go
@@ -359,41 +359,25 @@ func updateRepositoryProjectCount(ctx context.Context, repoID int64) error {
// ChangeProjectStatusByRepoIDAndID toggles a project between opened and closed
func ChangeProjectStatusByRepoIDAndID(ctx context.Context, repoID, projectID int64, isClosed bool) error {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- p := new(Project)
-
- has, err := db.GetEngine(ctx).ID(projectID).Where("repo_id = ?", repoID).Get(p)
- if err != nil {
- return err
- } else if !has {
- return ErrProjectNotExist{ID: projectID, RepoID: repoID}
- }
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ p := new(Project)
- if err := changeProjectStatus(ctx, p, isClosed); err != nil {
- return err
- }
+ has, err := db.GetEngine(ctx).ID(projectID).Where("repo_id = ?", repoID).Get(p)
+ if err != nil {
+ return err
+ } else if !has {
+ return ErrProjectNotExist{ID: projectID, RepoID: repoID}
+ }
- return committer.Commit()
+ return changeProjectStatus(ctx, p, isClosed)
+ })
}
// ChangeProjectStatus toggle a project between opened and closed
func ChangeProjectStatus(ctx context.Context, p *Project, isClosed bool) error {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- if err := changeProjectStatus(ctx, p, isClosed); err != nil {
- return err
- }
-
- return committer.Commit()
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ return changeProjectStatus(ctx, p, isClosed)
+ })
}
func changeProjectStatus(ctx context.Context, p *Project, isClosed bool) error {
diff --git a/models/repo.go b/models/repo.go
index 9bc67079a9..522debb9fe 100644
--- a/models/repo.go
+++ b/models/repo.go
@@ -290,19 +290,14 @@ func UpdateRepoStats(ctx context.Context, id int64) error {
}
func updateUserStarNumbers(ctx context.Context, users []user_model.User) error {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- for _, user := range users {
- if _, err = db.Exec(ctx, "UPDATE `user` SET num_stars=(SELECT COUNT(*) FROM `star` WHERE uid=?) WHERE id=?", user.ID, user.ID); err != nil {
- return err
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ for _, user := range users {
+ if _, err := db.Exec(ctx, "UPDATE `user` SET num_stars=(SELECT COUNT(*) FROM `star` WHERE uid=?) WHERE id=?", user.ID, user.ID); err != nil {
+ return err
+ }
}
- }
-
- return committer.Commit()
+ return nil
+ })
}
// DoctorUserStarNum recalculate Stars number for all user
diff --git a/models/repo/language_stats.go b/models/repo/language_stats.go
index 7db8cd4dd2..1cddd25f1d 100644
--- a/models/repo/language_stats.go
+++ b/models/repo/language_stats.go
@@ -141,101 +141,90 @@ func GetTopLanguageStats(ctx context.Context, repo *Repository, limit int) (Lang
// UpdateLanguageStats updates the language statistics for repository
func UpdateLanguageStats(ctx context.Context, repo *Repository, commitID string, stats map[string]int64) error {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
- sess := db.GetEngine(ctx)
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ sess := db.GetEngine(ctx)
- oldstats, err := GetLanguageStats(ctx, repo)
- if err != nil {
- return err
- }
- var topLang string
- var s int64
- for lang, size := range stats {
- if size > s {
- s = size
- topLang = lang
+ oldstats, err := GetLanguageStats(ctx, repo)
+ if err != nil {
+ return err
+ }
+ var topLang string
+ var s int64
+ for lang, size := range stats {
+ if size > s {
+ s = size
+ topLang = lang
+ }
}
- }
- for lang, size := range stats {
- upd := false
- for _, s := range oldstats {
- // Update already existing language
- if strings.EqualFold(s.Language, lang) {
- s.CommitID = commitID
- s.IsPrimary = lang == topLang
- s.Size = size
- if _, err := sess.ID(s.ID).Cols("`commit_id`", "`size`", "`is_primary`").Update(s); err != nil {
+ for lang, size := range stats {
+ upd := false
+ for _, s := range oldstats {
+ // Update already existing language
+ if strings.EqualFold(s.Language, lang) {
+ s.CommitID = commitID
+ s.IsPrimary = lang == topLang
+ s.Size = size
+ if _, err := sess.ID(s.ID).Cols("`commit_id`", "`size`", "`is_primary`").Update(s); err != nil {
+ return err
+ }
+ upd = true
+ break
+ }
+ }
+ // Insert new language
+ if !upd {
+ if err := db.Insert(ctx, &LanguageStat{
+ RepoID: repo.ID,
+ CommitID: commitID,
+ IsPrimary: lang == topLang,
+ Language: lang,
+ Size: size,
+ }); err != nil {
return err
}
- upd = true
- break
}
}
- // Insert new language
- if !upd {
- if err := db.Insert(ctx, &LanguageStat{
- RepoID: repo.ID,
- CommitID: commitID,
- IsPrimary: lang == topLang,
- Language: lang,
- Size: size,
- }); err != nil {
- return err
+ // Delete old languages
+ statsToDelete := make([]int64, 0, len(oldstats))
+ for _, s := range oldstats {
+ if s.CommitID != commitID {
+ statsToDelete = append(statsToDelete, s.ID)
}
}
- }
- // Delete old languages
- statsToDelete := make([]int64, 0, len(oldstats))
- for _, s := range oldstats {
- if s.CommitID != commitID {
- statsToDelete = append(statsToDelete, s.ID)
- }
- }
- if len(statsToDelete) > 0 {
- if _, err := sess.In("`id`", statsToDelete).Delete(&LanguageStat{}); err != nil {
- return err
+ if len(statsToDelete) > 0 {
+ if _, err := sess.In("`id`", statsToDelete).Delete(&LanguageStat{}); err != nil {
+ return err
+ }
}
- }
- // Update indexer status
- if err = UpdateIndexerStatus(ctx, repo, RepoIndexerTypeStats, commitID); err != nil {
- return err
- }
-
- return committer.Commit()
+ // Update indexer status
+ return UpdateIndexerStatus(ctx, repo, RepoIndexerTypeStats, commitID)
+ })
}
// CopyLanguageStat Copy originalRepo language stat information to destRepo (use for forked repo)
func CopyLanguageStat(ctx context.Context, originalRepo, destRepo *Repository) error {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- RepoLang := make(LanguageStatList, 0, 6)
- if err := db.GetEngine(ctx).Where("`repo_id` = ?", originalRepo.ID).Desc("`size`").Find(&RepoLang); err != nil {
- return err
- }
- if len(RepoLang) > 0 {
- for i := range RepoLang {
- RepoLang[i].ID = 0
- RepoLang[i].RepoID = destRepo.ID
- RepoLang[i].CreatedUnix = timeutil.TimeStampNow()
- }
- // update destRepo's indexer status
- tmpCommitID := RepoLang[0].CommitID
- if err := UpdateIndexerStatus(ctx, destRepo, RepoIndexerTypeStats, tmpCommitID); err != nil {
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ RepoLang := make(LanguageStatList, 0, 6)
+ if err := db.GetEngine(ctx).Where("`repo_id` = ?", originalRepo.ID).Desc("`size`").Find(&RepoLang); err != nil {
return err
}
- if err := db.Insert(ctx, &RepoLang); err != nil {
- return err
+ if len(RepoLang) > 0 {
+ for i := range RepoLang {
+ RepoLang[i].ID = 0
+ RepoLang[i].RepoID = destRepo.ID
+ RepoLang[i].CreatedUnix = timeutil.TimeStampNow()
+ }
+ // update destRepo's indexer status
+ tmpCommitID := RepoLang[0].CommitID
+ if err := UpdateIndexerStatus(ctx, destRepo, RepoIndexerTypeStats, tmpCommitID); err != nil {
+ return err
+ }
+ if err := db.Insert(ctx, &RepoLang); err != nil {
+ return err
+ }
}
- }
- return committer.Commit()
+ return nil
+ })
}
diff --git a/models/repo/release.go b/models/repo/release.go
index 59f4caf5aa..0db57503ce 100644
--- a/models/repo/release.go
+++ b/models/repo/release.go
@@ -472,30 +472,24 @@ func (r *Release) GetExternalID() int64 { return r.OriginalAuthorID }
// InsertReleases migrates release
func InsertReleases(ctx context.Context, rels ...*Release) error {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
- sess := db.GetEngine(ctx)
-
- for _, rel := range rels {
- if _, err := sess.NoAutoTime().Insert(rel); err != nil {
- return err
- }
-
- if len(rel.Attachments) > 0 {
- for i := range rel.Attachments {
- rel.Attachments[i].ReleaseID = rel.ID
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ for _, rel := range rels {
+ if _, err := db.GetEngine(ctx).NoAutoTime().Insert(rel); err != nil {
+ return err
}
- if _, err := sess.NoAutoTime().Insert(rel.Attachments); err != nil {
- return err
+ if len(rel.Attachments) > 0 {
+ for i := range rel.Attachments {
+ rel.Attachments[i].ReleaseID = rel.ID
+ }
+
+ if _, err := db.GetEngine(ctx).NoAutoTime().Insert(rel.Attachments); err != nil {
+ return err
+ }
}
}
- }
-
- return committer.Commit()
+ return nil
+ })
}
func FindTagsByCommitIDs(ctx context.Context, repoID int64, commitIDs ...string) (map[string][]*Release, error) {
diff --git a/models/repo/star.go b/models/repo/star.go
index 4c66855525..bc865f8373 100644
--- a/models/repo/star.go
+++ b/models/repo/star.go
@@ -25,48 +25,45 @@ func init() {
// StarRepo or unstar repository.
func StarRepo(ctx context.Context, doer *user_model.User, repo *Repository, star bool) error {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
- staring := IsStaring(ctx, doer.ID, repo.ID)
-
- if star {
- if user_model.IsUserBlockedBy(ctx, doer, repo.OwnerID) {
- return user_model.ErrBlockedUser
- }
-
- if staring {
- return nil
- }
-
- if err := db.Insert(ctx, &Star{UID: doer.ID, RepoID: repo.ID}); err != nil {
- return err
- }
- if _, err := db.Exec(ctx, "UPDATE `repository` SET num_stars = num_stars + 1 WHERE id = ?", repo.ID); err != nil {
- return err
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ staring := IsStaring(ctx, doer.ID, repo.ID)
+
+ if star {
+ if user_model.IsUserBlockedBy(ctx, doer, repo.OwnerID) {
+ return user_model.ErrBlockedUser
+ }
+
+ if staring {
+ return nil
+ }
+
+ if err := db.Insert(ctx, &Star{UID: doer.ID, RepoID: repo.ID}); err != nil {
+ return err
+ }
+ if _, err := db.Exec(ctx, "UPDATE `repository` SET num_stars = num_stars + 1 WHERE id = ?", repo.ID); err != nil {
+ return err
+ }
+ if _, err := db.Exec(ctx, "UPDATE `user` SET num_stars = num_stars + 1 WHERE id = ?", doer.ID); err != nil {
+ return err
+ }
+ } else {
+ if !staring {
+ return nil
+ }
+
+ if _, err := db.DeleteByBean(ctx, &Star{UID: doer.ID, RepoID: repo.ID}); err != nil {
+ return err
+ }
+ if _, err := db.Exec(ctx, "UPDATE `repository` SET num_stars = num_stars - 1 WHERE id = ?", repo.ID); err != nil {
+ return err
+ }
+ if _, err := db.Exec(ctx, "UPDATE `user` SET num_stars = num_stars - 1 WHERE id = ?", doer.ID); err != nil {
+ return err
+ }
}
- if _, err := db.Exec(ctx, "UPDATE `user` SET num_stars = num_stars + 1 WHERE id = ?", doer.ID); err != nil {
- return err
- }
- } else {
- if !staring {
- return nil
- }
-
- if _, err := db.DeleteByBean(ctx, &Star{UID: doer.ID, RepoID: repo.ID}); err != nil {
- return err
- }
- if _, err := db.Exec(ctx, "UPDATE `repository` SET num_stars = num_stars - 1 WHERE id = ?", repo.ID); err != nil {
- return err
- }
- if _, err := db.Exec(ctx, "UPDATE `user` SET num_stars = num_stars - 1 WHERE id = ?", doer.ID); err != nil {
- return err
- }
- }
- return committer.Commit()
+ return nil
+ })
}
// IsStaring checks if user has starred given repository.
diff --git a/models/repo/topic.go b/models/repo/topic.go
index 430a60f603..baeae01efa 100644
--- a/models/repo/topic.go
+++ b/models/repo/topic.go
@@ -227,32 +227,26 @@ func GetRepoTopicByName(ctx context.Context, repoID int64, topicName string) (*T
// AddTopic adds a topic name to a repository (if it does not already have it)
func AddTopic(ctx context.Context, repoID int64, topicName string) (*Topic, error) {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return nil, err
- }
- defer committer.Close()
- sess := db.GetEngine(ctx)
-
- topic, err := GetRepoTopicByName(ctx, repoID, topicName)
- if err != nil {
- return nil, err
- }
- if topic != nil {
- // Repo already have topic
- return topic, nil
- }
-
- topic, err = addTopicByNameToRepo(ctx, repoID, topicName)
- if err != nil {
- return nil, err
- }
+ return db.WithTx2(ctx, func(ctx context.Context) (*Topic, error) {
+ topic, err := GetRepoTopicByName(ctx, repoID, topicName)
+ if err != nil {
+ return nil, err
+ }
+ if topic != nil {
+ // Repo already have topic
+ return topic, nil
+ }
- if err = syncTopicsInRepository(sess, repoID); err != nil {
- return nil, err
- }
+ topic, err = addTopicByNameToRepo(ctx, repoID, topicName)
+ if err != nil {
+ return nil, err
+ }
- return topic, committer.Commit()
+ if err = syncTopicsInRepository(ctx, repoID); err != nil {
+ return nil, err
+ }
+ return topic, nil
+ })
}
// DeleteTopic removes a topic name from a repository (if it has it)
@@ -266,14 +260,15 @@ func DeleteTopic(ctx context.Context, repoID int64, topicName string) (*Topic, e
return nil, nil
}
- err = removeTopicFromRepo(ctx, repoID, topic)
- if err != nil {
- return nil, err
- }
-
- err = syncTopicsInRepository(db.GetEngine(ctx), repoID)
-
- return topic, err
+ return db.WithTx2(ctx, func(ctx context.Context) (*Topic, error) {
+ if err = removeTopicFromRepo(ctx, repoID, topic); err != nil {
+ return nil, err
+ }
+ if err = syncTopicsInRepository(ctx, repoID); err != nil {
+ return nil, err
+ }
+ return topic, nil
+ })
}
// SaveTopics save topics to a repository
@@ -285,64 +280,55 @@ func SaveTopics(ctx context.Context, repoID int64, topicNames ...string) error {
return err
}
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
- sess := db.GetEngine(ctx)
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ var addedTopicNames []string
+ for _, topicName := range topicNames {
+ if strings.TrimSpace(topicName) == "" {
+ continue
+ }
- var addedTopicNames []string
- for _, topicName := range topicNames {
- if strings.TrimSpace(topicName) == "" {
- continue
+ var found bool
+ for _, t := range topics {
+ if strings.EqualFold(topicName, t.Name) {
+ found = true
+ break
+ }
+ }
+ if !found {
+ addedTopicNames = append(addedTopicNames, topicName)
+ }
}
- var found bool
+ var removeTopics []*Topic
for _, t := range topics {
- if strings.EqualFold(topicName, t.Name) {
- found = true
- break
+ var found bool
+ for _, topicName := range topicNames {
+ if strings.EqualFold(topicName, t.Name) {
+ found = true
+ break
+ }
}
- }
- if !found {
- addedTopicNames = append(addedTopicNames, topicName)
- }
- }
-
- var removeTopics []*Topic
- for _, t := range topics {
- var found bool
- for _, topicName := range topicNames {
- if strings.EqualFold(topicName, t.Name) {
- found = true
- break
+ if !found {
+ removeTopics = append(removeTopics, t)
}
}
- if !found {
- removeTopics = append(removeTopics, t)
- }
- }
- for _, topicName := range addedTopicNames {
- _, err := addTopicByNameToRepo(ctx, repoID, topicName)
- if err != nil {
- return err
+ for _, topicName := range addedTopicNames {
+ _, err := addTopicByNameToRepo(ctx, repoID, topicName)
+ if err != nil {
+ return err
+ }
}
- }
- for _, topic := range removeTopics {
- err := removeTopicFromRepo(ctx, repoID, topic)
- if err != nil {
- return err
+ for _, topic := range removeTopics {
+ err := removeTopicFromRepo(ctx, repoID, topic)
+ if err != nil {
+ return err
+ }
}
- }
- if err := syncTopicsInRepository(sess, repoID); err != nil {
- return err
- }
-
- return committer.Commit()
+ return syncTopicsInRepository(ctx, repoID)
+ })
}
// GenerateTopics generates topics from a template repository
@@ -353,19 +339,19 @@ func GenerateTopics(ctx context.Context, templateRepo, generateRepo *Repository)
}
}
- return syncTopicsInRepository(db.GetEngine(ctx), generateRepo.ID)
+ return syncTopicsInRepository(ctx, generateRepo.ID)
}
// syncTopicsInRepository makes sure topics in the topics table are copied into the topics field of the repository
-func syncTopicsInRepository(sess db.Engine, repoID int64) error {
+func syncTopicsInRepository(ctx context.Context, repoID int64) error {
topicNames := make([]string, 0, 25)
- if err := sess.Table("topic").Cols("name").
+ if err := db.GetEngine(ctx).Table("topic").Cols("name").
Join("INNER", "repo_topic", "repo_topic.topic_id = topic.id").
Where("repo_topic.repo_id = ?", repoID).Asc("topic.name").Find(&topicNames); err != nil {
return err
}
- if _, err := sess.ID(repoID).Cols("topics").Update(&Repository{
+ if _, err := db.GetEngine(ctx).ID(repoID).Cols("topics").Update(&Repository{
Topics: topicNames,
}); err != nil {
return err
diff --git a/models/repo/update.go b/models/repo/update.go
index 64065f11c4..3228ae11a4 100644
--- a/models/repo/update.go
+++ b/models/repo/update.go
@@ -19,11 +19,6 @@ func UpdateRepositoryOwnerNames(ctx context.Context, ownerID int64, ownerName st
if ownerID == 0 {
return nil
}
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
if _, err := db.GetEngine(ctx).Where("owner_id = ?", ownerID).Cols("owner_name").NoAutoTime().Update(&Repository{
OwnerName: ownerName,
@@ -31,7 +26,7 @@ func UpdateRepositoryOwnerNames(ctx context.Context, ownerID int64, ownerName st
return err
}
- return committer.Commit()
+ return nil
}
// UpdateRepositoryUpdatedTime updates a repository's updated time
diff --git a/models/repo/upload.go b/models/repo/upload.go
index 20a8fa26fe..f7d4749842 100644
--- a/models/repo/upload.go
+++ b/models/repo/upload.go
@@ -117,12 +117,6 @@ func DeleteUploads(ctx context.Context, uploads ...*Upload) (err error) {
return nil
}
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
ids := make([]int64, len(uploads))
for i := range uploads {
ids[i] = uploads[i].ID
@@ -131,10 +125,6 @@ func DeleteUploads(ctx context.Context, uploads ...*Upload) (err error) {
return fmt.Errorf("delete uploads: %w", err)
}
- if err = committer.Commit(); err != nil {
- return err
- }
-
for _, upload := range uploads {
localPath := upload.LocalPath()
isFile, err := util.IsFile(localPath)
diff --git a/models/user/email_address.go b/models/user/email_address.go
index 2ba6a56450..cb423945f8 100644
--- a/models/user/email_address.go
+++ b/models/user/email_address.go
@@ -256,15 +256,9 @@ func IsEmailUsed(ctx context.Context, email string) (bool, error) {
// ActivateEmail activates the email address to given user.
func ActivateEmail(ctx context.Context, email *EmailAddress) error {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
- if err := updateActivation(ctx, email, true); err != nil {
- return err
- }
- return committer.Commit()
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ return updateActivation(ctx, email, true)
+ })
}
func updateActivation(ctx context.Context, email *EmailAddress, activate bool) error {
@@ -305,33 +299,30 @@ func makeEmailPrimaryInternal(ctx context.Context, emailID int64, isActive bool)
return ErrUserNotExist{UID: email.UID}
}
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
- sess := db.GetEngine(ctx)
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ sess := db.GetEngine(ctx)
- // 1. Update user table
- user.Email = email.Email
- if _, err = sess.ID(user.ID).Cols("email").Update(user); err != nil {
- return err
- }
+ // 1. Update user table
+ user.Email = email.Email
+ if _, err := sess.ID(user.ID).Cols("email").Update(user); err != nil {
+ return err
+ }
- // 2. Update old primary email
- if _, err = sess.Where("uid=? AND is_primary=?", email.UID, true).Cols("is_primary").Update(&EmailAddress{
- IsPrimary: false,
- }); err != nil {
- return err
- }
+ // 2. Update old primary email
+ if _, err := sess.Where("uid=? AND is_primary=?", email.UID, true).Cols("is_primary").Update(&EmailAddress{
+ IsPrimary: false,
+ }); err != nil {
+ return err
+ }
- // 3. update new primary email
- email.IsPrimary = true
- if _, err = sess.ID(email.ID).Cols("is_primary").Update(email); err != nil {
- return err
- }
+ // 3. update new primary email
+ email.IsPrimary = true
+ if _, err := sess.ID(email.ID).Cols("is_primary").Update(email); err != nil {
+ return err
+ }
- return committer.Commit()
+ return nil
+ })
}
// ChangeInactivePrimaryEmail replaces the inactive primary email of a given user
diff --git a/models/user/follow.go b/models/user/follow.go
index cf9672109a..e098caab5b 100644
--- a/models/user/follow.go
+++ b/models/user/follow.go
@@ -38,24 +38,20 @@ func FollowUser(ctx context.Context, user, follow *User) (err error) {
return ErrBlockedUser
}
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- if err = db.Insert(ctx, &Follow{UserID: user.ID, FollowID: follow.ID}); err != nil {
- return err
- }
-
- if _, err = db.Exec(ctx, "UPDATE `user` SET num_followers = num_followers + 1 WHERE id = ?", follow.ID); err != nil {
- return err
- }
-
- if _, err = db.Exec(ctx, "UPDATE `user` SET num_following = num_following + 1 WHERE id = ?", user.ID); err != nil {
- return err
- }
- return committer.Commit()
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ if err = db.Insert(ctx, &Follow{UserID: user.ID, FollowID: follow.ID}); err != nil {
+ return err
+ }
+
+ if _, err = db.Exec(ctx, "UPDATE `user` SET num_followers = num_followers + 1 WHERE id = ?", follow.ID); err != nil {
+ return err
+ }
+
+ if _, err = db.Exec(ctx, "UPDATE `user` SET num_following = num_following + 1 WHERE id = ?", user.ID); err != nil {
+ return err
+ }
+ return nil
+ })
}
// UnfollowUser unmarks someone as another's follower.
@@ -64,22 +60,18 @@ func UnfollowUser(ctx context.Context, userID, followID int64) (err error) {
return nil
}
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ if _, err = db.DeleteByBean(ctx, &Follow{UserID: userID, FollowID: followID}); err != nil {
+ return err
+ }
- if _, err = db.DeleteByBean(ctx, &Follow{UserID: userID, FollowID: followID}); err != nil {
- return err
- }
+ if _, err = db.Exec(ctx, "UPDATE `user` SET num_followers = num_followers - 1 WHERE id = ?", followID); err != nil {
+ return err
+ }
- if _, err = db.Exec(ctx, "UPDATE `user` SET num_followers = num_followers - 1 WHERE id = ?", followID); err != nil {
- return err
- }
-
- if _, err = db.Exec(ctx, "UPDATE `user` SET num_following = num_following - 1 WHERE id = ?", userID); err != nil {
- return err
- }
- return committer.Commit()
+ if _, err = db.Exec(ctx, "UPDATE `user` SET num_following = num_following - 1 WHERE id = ?", userID); err != nil {
+ return err
+ }
+ return nil
+ })
}
diff --git a/models/webhook/webhook.go b/models/webhook/webhook.go
index b234d9ffee..7d4b2e2237 100644
--- a/models/webhook/webhook.go
+++ b/models/webhook/webhook.go
@@ -319,21 +319,16 @@ func UpdateWebhookLastStatus(ctx context.Context, w *Webhook) error {
// DeleteWebhookByID uses argument bean as query condition,
// ID must be specified and do not assign unnecessary fields.
func DeleteWebhookByID(ctx context.Context, id int64) (err error) {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- if count, err := db.DeleteByID[Webhook](ctx, id); err != nil {
- return err
- } else if count == 0 {
- return ErrWebhookNotExist{ID: id}
- } else if _, err = db.DeleteByBean(ctx, &HookTask{HookID: id}); err != nil {
- return err
- }
-
- return committer.Commit()
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ if count, err := db.DeleteByID[Webhook](ctx, id); err != nil {
+ return err
+ } else if count == 0 {
+ return ErrWebhookNotExist{ID: id}
+ } else if _, err = db.DeleteByBean(ctx, &HookTask{HookID: id}); err != nil {
+ return err
+ }
+ return nil
+ })
}
// DeleteWebhookByRepoID deletes webhook of repository by given ID.
diff --git a/modules/structs/issue.go b/modules/structs/issue.go
index df0be8f9ec..322ac1e4ca 100644
--- a/modules/structs/issue.go
+++ b/modules/structs/issue.go
@@ -262,7 +262,8 @@ func (it IssueTemplate) Type() IssueTemplateType {
// IssueMeta basic issue information
// swagger:model
type IssueMeta struct {
- Index int64 `json:"index"`
+ Index int64 `json:"index"`
+ // owner of the issue's repo
Owner string `json:"owner"`
Name string `json:"repo"`
}
diff --git a/modules/structs/repo.go b/modules/structs/repo.go
index aca5d9c3f4..f2e11b1542 100644
--- a/modules/structs/repo.go
+++ b/modules/structs/repo.go
@@ -48,15 +48,16 @@ type ExternalWiki struct {
// Repository represents a repository
type Repository struct {
- ID int64 `json:"id"`
- Owner *User `json:"owner"`
- Name string `json:"name"`
- FullName string `json:"full_name"`
- Description string `json:"description"`
- Empty bool `json:"empty"`
- Private bool `json:"private"`
- Fork bool `json:"fork"`
- Template bool `json:"template"`
+ ID int64 `json:"id"`
+ Owner *User `json:"owner"`
+ Name string `json:"name"`
+ FullName string `json:"full_name"`
+ Description string `json:"description"`
+ Empty bool `json:"empty"`
+ Private bool `json:"private"`
+ Fork bool `json:"fork"`
+ Template bool `json:"template"`
+ // the original repository if this repository is a fork, otherwise null
Parent *Repository `json:"parent,omitempty"`
Mirror bool `json:"mirror"`
Size int `json:"size"`
@@ -225,15 +226,13 @@ type EditRepoOption struct {
EnablePrune *bool `json:"enable_prune,omitempty"`
}
-// GenerateRepoOption options when creating repository using a template
+// GenerateRepoOption options when creating a repository using a template
// swagger:model
type GenerateRepoOption struct {
- // The organization or person who will own the new repository
+ // the organization's name or individual user's name who will own the new repository
//
// required: true
Owner string `json:"owner"`
- // Name of the repository to create
- //
// required: true
// unique: true
Name string `json:"name" binding:"Required;AlphaDashDot;MaxSize(100)"`
@@ -352,9 +351,9 @@ func (gt GitServiceType) Title() string {
type MigrateRepoOptions struct {
// required: true
CloneAddr string `json:"clone_addr" binding:"Required"`
- // deprecated (only for backwards compatibility)
+ // deprecated (only for backwards compatibility, use repo_owner instead)
RepoOwnerID int64 `json:"uid"`
- // Name of User or Organisation who will own Repo after migration
+ // the organization's name or individual user's name who will own the migrated repository
RepoOwner string `json:"repo_owner"`
// required: true
RepoName string `json:"repo_name" binding:"Required;AlphaDashDot;MaxSize(100)"`
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index c1a3d37037..65ba4e9cd3 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -44,7 +44,7 @@ webauthn_use_twofa = Use a two-factor code from your phone
webauthn_error = Could not read your security key.
webauthn_unsupported_browser = Your browser does not currently support WebAuthn.
webauthn_error_unknown = An unknown error occurred. Please retry.
-webauthn_error_insecure = WebAuthn only supports secure connections. For testing over HTTP, you can use the origin "localhost" or "127.0.0.1"
+webauthn_error_insecure = WebAuthn only supports secure connections. For testing over HTTP, you can use the origin "localhost" or "127.0.0.1".
webauthn_error_unable_to_process = The server could not process your request.
webauthn_error_duplicated = The security key is not permitted for this request. Please make sure that the key is not already registered.
webauthn_error_empty = You must set a name for this key.
@@ -168,7 +168,7 @@ no_results_found = No results found.
internal_error_skipped = Internal error occurred but is skipped: %s
[search]
-search = Search...
+search = Search…
type_tooltip = Search type
fuzzy = Fuzzy
fuzzy_tooltip = Include results that closely match the search term
@@ -178,23 +178,23 @@ regexp = Regexp
regexp_tooltip = Include only results that match the regexp search term
exact = Exact
exact_tooltip = Include only results that match the exact search term
-repo_kind = Search repos...
-user_kind = Search users...
-org_kind = Search orgs...
-team_kind = Search teams...
-code_kind = Search code...
+repo_kind = Search repos…
+user_kind = Search users…
+org_kind = Search orgs…
+team_kind = Search teams…
+code_kind = Search code…
code_search_unavailable = Code search is currently not available. Please contact the site administrator.
code_search_by_git_grep = Current code search results are provided by "git grep". There might be better results if site administrator enables Repository Indexer.
-package_kind = Search packages...
-project_kind = Search projects...
-branch_kind = Search branches...
-tag_kind = Search tags...
+package_kind = Search packages…
+project_kind = Search projects…
+branch_kind = Search branches…
+tag_kind = Search tags…
tag_tooltip = Search for matching tags. Use '%' to match any sequence of numbers.
-commit_kind = Search commits...
-runner_kind = Search runners...
+commit_kind = Search commits…
+runner_kind = Search runners…
no_results = No matching results found.
-issue_kind = Search issues...
-pull_kind = Search pulls...
+issue_kind = Search issues…
+pull_kind = Search pull requests…
keyword_search_unavailable = Searching by keyword is currently not available. Please contact the site administrator.
[aria]
@@ -230,8 +230,8 @@ buttons.enable_monospace_font = Enable monospace font
buttons.disable_monospace_font = Disable monospace font
[filter]
-string.asc = A - Z
-string.desc = Z - A
+string.asc = A–Z
+string.desc = Z–A
[error]
occurred = An error occurred
@@ -252,7 +252,7 @@ license_desc = Go get <a target="_blank" rel="noopener noreferrer" href="%[1]s">
[install]
install = Installation
-installing_desc = Installing now, please wait...
+installing_desc = Installing now, please wait…
title = Initial Configuration
docker_helper = If you run Gitea inside Docker, please read the <a target="_blank" rel="noopener noreferrer" href="%s">documentation</a> before changing any settings.
require_db_desc = Gitea requires MySQL, PostgreSQL, MSSQL, SQLite3 or TiDB (MySQL protocol).
@@ -269,16 +269,16 @@ path = Path
sqlite_helper = File path for the SQLite3 database.<br>Enter an absolute path if you run Gitea as a service.
reinstall_error = You are trying to install into an existing Gitea database
reinstall_confirm_message = Re-installing with an existing Gitea database can cause multiple problems. In most cases, you should use your existing "app.ini" to run Gitea. If you know what you are doing, confirm the following:
-reinstall_confirm_check_1 = The data encrypted by the SECRET_KEY in app.ini may be lost: users may not be able to log in with 2FA/OTP & mirrors may not function correctly. By checking this box you confirm that the current app.ini file contains the correct the SECRET_KEY.
-reinstall_confirm_check_2 = The repositories and settings may need to be re-synchronized. By checking this box you confirm that you will resynchronize the hooks for the repositories and authorized_keys file manually. You confirm that you will ensure that repository and mirror settings are correct.
+reinstall_confirm_check_1 = The data encrypted by the SECRET_KEY in app.ini may be lost: users may not be able to log in with 2FA/OTP and mirrors may not function correctly. By checking this box, you confirm that the current app.ini file contains the correct the SECRET_KEY.
+reinstall_confirm_check_2 = The repositories and settings may need to be resynchronized. By checking this box, you confirm that you will resynchronize the hooks for the repositories and authorized_keys file manually. You confirm that you will ensure that repository and mirror settings are correct.
reinstall_confirm_check_3 = You confirm that you are absolutely sure that this Gitea is running with the correct app.ini location and that you are sure that you have to re-install. You confirm that you acknowledge the above risks.
err_empty_db_path = The SQLite3 database path cannot be empty.
no_admin_and_disable_registration = You cannot disable user self-registration without creating an administrator account.
err_empty_admin_password = The administrator password cannot be empty.
-err_empty_admin_email = The administrator email cannot be empty.
-err_admin_name_is_reserved = Administrator Username is invalid, username is reserved
-err_admin_name_pattern_not_allowed = Administrator username is invalid, the username matches a reserved pattern
-err_admin_name_is_invalid = Administrator Username is invalid
+err_empty_admin_email = The administrator email address cannot be empty.
+err_admin_name_is_reserved = Administrator username is invalid. Username is reserved.
+err_admin_name_pattern_not_allowed = Administrator username is invalid. The username matches a reserved pattern.
+err_admin_name_is_invalid = Administrator username is invalid
general_title = General Settings
app_name = Site Title
@@ -294,7 +294,7 @@ domain_helper = Domain or host address for the server.
ssh_port = SSH Server Port
ssh_port_helper = Port number your SSH server listens on. Leave empty to disable.
http_port = Gitea HTTP Listen Port
-http_port_helper = Port number the Giteas web server will listen on.
+http_port_helper = Port number the Gitea web server will listen on.
app_url = Gitea Base URL
app_url_helper = Base address for HTTP(S) clone URLs and email notifications.
log_root_path = Log Path
@@ -430,8 +430,8 @@ allow_password_change = Require user to change password (recommended)
reset_password_mail_sent_prompt = A confirmation email has been sent to <b>%s</b>. Please check your inbox within the next %s to complete the account recovery process.
active_your_account = Activate Your Account
account_activated = Account has been activated
-prohibit_login = Sign In Prohibited
-prohibit_login_desc = Your account is prohibited from signing in, please contact your site administrator.
+prohibit_login = Sign-In Prohibited
+prohibit_login_desc = Your account is prohibited from signing in. Please contact your site administrator.
resent_limit_prompt = You have already requested an activation email recently. Please wait 3 minutes and try again.
has_unconfirmed_mail = Hi %s, you have an unconfirmed email address (<b>%s</b>). If you haven't received a confirmation email or need to resend a new one, please click on the button below.
change_unconfirmed_mail_address = If your registration email address is incorrect, you can change it here and resend a new confirmation email.
@@ -452,7 +452,7 @@ use_scratch_code = Use a scratch code
twofa_scratch_used = You have used your scratch code. You have been redirected to the two-factor settings page so you may remove your device enrollment or generate a new scratch code.
twofa_passcode_incorrect = Your passcode is incorrect. If you misplaced your device, use your scratch code to sign in.
twofa_scratch_token_incorrect = Your scratch code is incorrect.
-twofa_required = You must set up Two-Factor Authentication to get access to repositories, or try to log in again.
+twofa_required = You must set up two-factor authentication to get access to repositories, or try to log in again.
login_userpass = Sign In
login_openid = OpenID
oauth_signup_tab = Register New Account
@@ -471,17 +471,17 @@ openid_connect_desc = The chosen OpenID URI is unknown. Associate it with a new
openid_register_title = Create new account
openid_register_desc = The chosen OpenID URI is unknown. Associate it with a new account here.
openid_signin_desc = Enter your OpenID URI. For example: alice.openid.example.org or https://openid.example.org/alice.
-disable_forgot_password_mail = Account recovery is disabled because no email is set up. Please contact your site administrator.
-disable_forgot_password_mail_admin = Account recovery is only available when email is set up. Please set up email to enable account recovery.
+disable_forgot_password_mail = Account recovery is disabled because no email address is set up. Please contact your site administrator.
+disable_forgot_password_mail_admin = Account recovery is only available when an email address is set up.
email_domain_blacklisted = You cannot register with your email address.
authorize_application = Authorize Application
authorize_redirect_notice = You will be redirected to %s if you authorize this application.
authorize_application_created_by = This application was created by %s.
-authorize_application_description = If you grant access, it will be able to access and write to all your account information, including private repos and organisations.
+authorize_application_description = If you grant access, it will be able to access and write to all your account information, including private repos and organizations.
authorize_application_with_scopes = With scopes: %s
authorize_title = Authorize "%s" to access your account?
authorization_failed = Authorization failed
-authorization_failed_desc = The authorization failed because we detected an invalid request. Please contact the maintainer of the app you have tried to authorize.
+authorization_failed_desc = The authorization failed because we detected an invalid request. Please contact the maintainer of the app you tried to authorize.
sspi_auth_failed = SSPI authentication failed
password_pwned = The password you chose is on a <a target="_blank" rel="noopener noreferrer" href="%s">list of stolen passwords</a> previously exposed in public data breaches. Please try again with a different password and consider changing this password elsewhere too.
password_pwned_err = Could not complete request to HaveIBeenPwned
@@ -545,7 +545,7 @@ release.download.targz = Source Code (TAR.GZ)
repo.transfer.subject_to = %s would like to transfer "%s" to %s
repo.transfer.subject_to_you = %s would like to transfer "%s" to you
repo.transfer.to_you = you
-repo.transfer.body = To accept or reject it visit %s or just ignore it.
+repo.transfer.body = To accept or reject it, visit %s or just ignore it.
repo.collaborator.added.subject = %s added you to %s
repo.collaborator.added.text = You have been added as a collaborator of repository:
@@ -597,7 +597,7 @@ url_error = `"%s" is not a valid URL.`
include_error = ` must contain substring "%s".`
glob_pattern_error = ` glob pattern is invalid: %s.`
regex_pattern_error = ` regex pattern is invalid: %s.`
-username_error = ` can only contain alphanumeric chars ('0-9','a-z','A-Z'), dash ('-'), underscore ('_') and dot ('.'). It cannot begin or end with non-alphanumeric chars, and consecutive non-alphanumeric chars are also forbidden.`
+username_error = ` can only contain alphanumeric characters ('0-9','a-z','A-Z'), dash ('-'), underscore ('_') and dot ('.'). It cannot begin or end with non-alphanumeric characters, and consecutive non-alphanumeric characters are also forbidden.`
invalid_group_team_map_error = ` mapping is invalid: %s`
unknown_error = Unknown error:
captcha_incorrect = The CAPTCHA code is incorrect.
@@ -612,17 +612,17 @@ username_has_not_been_changed = Username has not been changed
repo_name_been_taken = The repository name is already used.
repository_force_private = Force Private is enabled: private repositories cannot be made public.
repository_files_already_exist = Files already exist for this repository. Contact the system administrator.
-repository_files_already_exist.adopt = Files already exist for this repository and can only be Adopted.
+repository_files_already_exist.adopt = Files already exist for this repository and can only be adopted.
repository_files_already_exist.delete = Files already exist for this repository. You must delete them.
repository_files_already_exist.adopt_or_delete = Files already exist for this repository. Either adopt them or delete them.
visit_rate_limit = Remote visit addressed rate limitation.
-2fa_auth_required = Remote visit required two factors authentication.
+2fa_auth_required = Remote visit required two-factor authentication.
org_name_been_taken = The organization name is already taken.
team_name_been_taken = The team name is already taken.
team_no_units_error = Allow access to at least one repository section.
email_been_used = The email address is already used.
email_invalid = The email address is invalid.
-email_domain_is_not_allowed = The domain of user email <b>%s</b> conflicts with EMAIL_DOMAIN_ALLOWLIST or EMAIL_DOMAIN_BLOCKLIST. Please ensure your operation is expected.
+email_domain_is_not_allowed = The domain of user email address <b>%s</b> conflicts with EMAIL_DOMAIN_ALLOWLIST or EMAIL_DOMAIN_BLOCKLIST. Please ensure your operation is expected.
openid_been_used = The OpenID address "%s" is already used.
username_password_incorrect = Username or password is incorrect.
password_complexity = Password does not pass complexity requirements:
@@ -647,14 +647,14 @@ invalid_ssh_key = Cannot verify your SSH key: %s
invalid_gpg_key = Cannot verify your GPG key: %s
invalid_ssh_principal = Invalid principal: %s
must_use_public_key = The key you provided is a private key. Please do not upload your private key anywhere. Use your public key instead.
-unable_verify_ssh_key = "Cannot verify the SSH key, double-check it for mistakes."
+unable_verify_ssh_key = "Cannot verify the SSH key. Double-check it for mistakes."
auth_failed = Authentication failed: %v
-still_own_repo = "Your account owns one or more repositories, delete or transfer them first."
-still_has_org = "Your account is a member of one or more organizations, leave them first."
-still_own_packages = "Your account owns one or more packages, delete them first."
-org_still_own_repo = "This organization still owns one or more repositories, delete or transfer them first."
-org_still_own_packages = "This organization still owns one or more packages, delete them first."
+still_own_repo = "Your account owns one or more repositories. Delete or transfer them first."
+still_has_org = "Your account is a member of one or more organizations. Leave them first."
+still_own_packages = "Your account owns one or more packages. Delete them first."
+org_still_own_repo = "This organization still owns one or more repositories. Delete or transfer them first."
+org_still_own_packages = "This organization still owns one or more packages. Delete them first."
target_branch_not_exist = Target branch does not exist.
target_ref_not_exist = Target ref does not exist %s
@@ -685,7 +685,7 @@ settings = User Settings
form.name_reserved = The username "%s" is reserved.
form.name_pattern_not_allowed = The pattern "%s" is not allowed in a username.
-form.name_chars_not_allowed = User name "%s" contains invalid characters.
+form.name_chars_not_allowed = Username "%s" contains invalid characters.
block.block = Block
block.block.user = Block user
@@ -702,7 +702,7 @@ block.info_3 = send you notifications by @mentioning your username
block.info_4 = inviting you as a collaborator to their repositories
block.info_5 = starring, forking or watching on repositories
block.info_6 = opening and commenting on issues or pull requests
-block.info_7 = reacting on your comments in issues or pull requests
+block.info_7 = reacting to your comments in issues or pull requests
block.user_to_block = User to block
block.note = Note
block.note.title = Optional note:
@@ -753,7 +753,7 @@ cancel = Cancel
language = Language
ui = Theme
hidden_comment_types = Hidden comment types
-hidden_comment_types_description = Comment types checked here will not be shown inside issue pages. Checking "Label" for example removes all "{user} added/removed {label}" comments.
+hidden_comment_types_description = Comment types checked here will not be shown on issue pages. Checking "Label", for example, removes all "{user} added/removed {label}" comments.
hidden_comment_types.ref_tooltip = Comments where this issue was referenced from another issue/commit/…
hidden_comment_types.issue_ref_tooltip = Comments where the user changes the branch/tag associated with the issue
comment_type_group_reference = Reference
@@ -801,15 +801,15 @@ manage_themes = Select default theme
manage_openid = Manage OpenID Addresses
email_desc = Your primary email address will be used for notifications, password recovery and, provided that it is not hidden, web-based Git operations.
theme_desc = This will be your default theme across the site.
-theme_colorblindness_help = Colorblindness Theme Support
-theme_colorblindness_prompt = Gitea just gets some themes with basic colorblindness support, which only have a few colors defined. The work is still in progress. More improvements could be done by defining more colors in the theme CSS files.
+theme_colorblindness_help = Color blindness Theme Support
+theme_colorblindness_prompt = Gitea only has a few themes with basic color blindness support, which only have a few colors defined. The work is still in progress. More improvements could be made by defining more colors in the theme CSS files.
primary = Primary
activated = Activated
requires_activation = Requires activation
primary_email = Make Primary
activate_email = Send Activation
activations_pending = Activations Pending
-can_not_add_email_activations_pending = There is a pending activation, try again in a few minutes if you want to add a new email.
+can_not_add_email_activations_pending = There is a pending activation. Try again in a few minutes if you want to add a new email address.
delete_email = Remove
email_deletion = Remove Email Address
email_deletion_desc = This email address and related information will be removed from your account. Git commits by this email address will remain unchanged. Continue?
@@ -855,7 +855,7 @@ gpg_key_matched_identities_long=The embedded identities in this key match the fo
gpg_key_verified=Verified Key
gpg_key_verified_long=Key has been verified with a token and can be used to verify commits matching any activated email addresses for this user in addition to any matched identities for this key.
gpg_key_verify=Verify
-gpg_invalid_token_signature = The provided GPG key, signature and token do not match or token is out-of-date.
+gpg_invalid_token_signature = The provided GPG key, signature and token do not match, or the token is out-of-date.
gpg_token_required = You must provide a signature for the below token
gpg_token = Token
gpg_token_help = You can generate a signature using:
@@ -865,7 +865,7 @@ verify_gpg_key_success = GPG key "%s" has been verified.
ssh_key_verified=Verified Key
ssh_key_verified_long=Key has been verified with a token and can be used to verify commits matching any activated email addresses for this user.
ssh_key_verify=Verify
-ssh_invalid_token_signature = The provided SSH key, signature or token do not match or token is out-of-date.
+ssh_invalid_token_signature = The provided SSH key, signature or token do not match, or the token is out-of-date.
ssh_token_required = You must provide a signature for the below token
ssh_token = Token
ssh_token_help = You can generate a signature using:
@@ -886,7 +886,7 @@ gpg_key_deletion = Remove GPG Key
ssh_principal_deletion = Remove SSH Certificate Principal
ssh_key_deletion_desc = Removing an SSH key revokes its access to your account. Continue?
gpg_key_deletion_desc = Removing a GPG key un-verifies commits signed by it. Continue?
-ssh_principal_deletion_desc = Removing a SSH Certificate Principal revokes its access to your account. Continue?
+ssh_principal_deletion_desc = Removing an SSH Certificate Principal revokes its access to your account. Continue?
ssh_key_deletion_success = The SSH key has been removed.
gpg_key_deletion_success = The GPG key has been removed.
ssh_principal_deletion_success = The principal has been removed.
@@ -948,7 +948,7 @@ create_oauth2_application_button = Create Application
create_oauth2_application_success = You have successfully created a new OAuth2 application.
update_oauth2_application_success = You have successfully updated the OAuth2 application.
oauth2_application_name = Application Name
-oauth2_confidential_client = Confidential Client. Select for apps that keep the secret confidential, such as web apps. Do not select for native apps including desktop and mobile apps.
+oauth2_confidential_client = Confidential Client. Select for apps that keep the secret confidential, such as web apps. Do not select for native apps, including desktop and mobile apps.
oauth2_skip_secondary_authorization = Skip authorization for public clients after granting access once. <strong>May pose a security risk.</strong>
oauth2_redirect_uris = Redirect URIs. Please use a new line for every URI.
save_application = Save
@@ -963,10 +963,10 @@ oauth2_application_remove_description = Removing an OAuth2 application will prev
oauth2_application_locked = Gitea pre-registers some OAuth2 applications on startup if enabled in config. To prevent unexpected behavior, these can neither be edited nor removed. Please refer to the OAuth2 documentation for more information.
authorized_oauth2_applications = Authorized OAuth2 Applications
-authorized_oauth2_applications_description = You have granted access to your personal Gitea account to these third party applications. Please revoke access for applications you no longer need.
+authorized_oauth2_applications_description = You have granted access to your personal Gitea account to these third-party applications. Please revoke access for applications you no longer need.
revoke_key = Revoke
revoke_oauth2_grant = Revoke Access
-revoke_oauth2_grant_description = Revoking access for this third party application will prevent this application from accessing your data. Are you sure?
+revoke_oauth2_grant_description = Revoking access for this third-party application will prevent this application from accessing your data. Are you sure?
revoke_oauth2_grant_success = Access revoked successfully.
twofa_desc = To protect your account against password theft, you can use a smartphone or another device for receiving time-based one-time passwords ("TOTP").
@@ -976,7 +976,7 @@ twofa_not_enrolled = Your account is not currently enrolled in two-factor authen
twofa_disable = Disable Two-Factor Authentication
twofa_scratch_token_regenerate = Regenerate Single-Use Recovery Key
twofa_scratch_token_regenerated = Your single-use recovery key is now %s. Store it in a safe place, as it will not be shown again.
-twofa_enroll = Enroll into Two-Factor Authentication
+twofa_enroll = Enroll in Two-Factor Authentication
twofa_disable_note = You can disable two-factor authentication if needed.
twofa_disable_desc = Disabling two-factor authentication will make your account less secure. Continue?
regenerate_scratch_token_desc = If you misplaced your recovery key or have already used it to sign in, you can reset it here.
@@ -992,7 +992,7 @@ webauthn_desc = Security keys are hardware devices containing cryptographic keys
webauthn_register_key = Add Security Key
webauthn_nickname = Nickname
webauthn_delete_key = Remove Security Key
-webauthn_delete_key_desc = If you remove a security key you can no longer sign in with it. Continue?
+webauthn_delete_key_desc = If you remove a security key, you can no longer sign in with it. Continue?
webauthn_key_loss_warning = If you lose your security keys, you will lose access to your account.
webauthn_alternative_tip = You may want to configure an additional authentication method.
@@ -1109,7 +1109,7 @@ mirror_address_protocol_invalid = The provided URL is invalid. Only http(s):// o
mirror_lfs = Large File Storage (LFS)
mirror_lfs_desc = Activate mirroring of LFS data.
mirror_lfs_endpoint = LFS Endpoint
-mirror_lfs_endpoint_desc = Sync will attempt to use the clone url to <a target="_blank" rel="noopener noreferrer" href="%s">determine the LFS server</a>. You can also specify a custom endpoint if the repository LFS data is stored somewhere else.
+mirror_lfs_endpoint_desc = Sync will attempt to use the clone URL to <a target="_blank" rel="noopener noreferrer" href="%s">determine the LFS server</a>. You can also specify a custom endpoint if the repository LFS data is stored somewhere else.
mirror_last_synced = Last Synchronized
mirror_password_placeholder = (Unchanged)
mirror_password_blank_placeholder = (Unset)
@@ -1122,7 +1122,7 @@ stars = Stars
reactions_more = and %d more
unit_disabled = The site administrator has disabled this repository section.
language_other = Other
-adopt_search = Enter username to search for unadopted repositories... (leave blank to find all)
+adopt_search = Enter username to search for unadopted repositories… (leave blank to find all)
adopt_preexisting_label = Adopt Files
adopt_preexisting = Adopt pre-existing files
adopt_preexisting_content = Create repository from %s
@@ -1164,8 +1164,8 @@ template.issue_labels = Issue Labels
template.one_item = Must select at least one template item
template.invalid = Must select a template repository
-archive.title = This repo is archived. You can view files and clone it. You cannot open issues, pull requests or push a commit.
-archive.title_date = This repository has been archived on %s. You can view files and clone it. You cannot open issues, pull requests or push a commit.
+archive.title = This repo is archived. You can view files and clone it. You cannot open issues or pull requests or push a commit.
+archive.title_date = This repository has been archived on %s. You can view files and clone it. You cannot open issues or pull requests or push a commit.
archive.issue.nocomment = This repo is archived. You cannot comment on issues.
archive.pull.nocomment = This repo is archived. You cannot comment on pull requests.
@@ -1182,7 +1182,7 @@ migrate_options_lfs = Migrate LFS files
migrate_options_lfs_endpoint.label = LFS Endpoint
migrate_options_lfs_endpoint.description = Migration will attempt to use your Git remote to <a target="_blank" rel="noopener noreferrer" href="%s">determine the LFS server</a>. You can also specify a custom endpoint if the repository LFS data is stored somewhere else.
migrate_options_lfs_endpoint.description.local = A local server path is supported too.
-migrate_options_lfs_endpoint.placeholder = If left blank, the endpoint will be derived from the clone URL
+migrate_options_lfs_endpoint.placeholder = If left blank, the endpoint will be derived from the clone URL.
migrate_items = Migration Items
migrate_items_wiki = Wiki
migrate_items_milestones = Milestones
@@ -1194,10 +1194,10 @@ migrate_items_releases = Releases
migrate_repo = Migrate Repository
migrate.clone_address = Migrate / Clone From URL
migrate.clone_address_desc = The HTTP(S) or Git 'clone' URL of an existing repository
-migrate.github_token_desc = You can put one or more tokens here separated by commas to make migrating faster by circumventing the GitHub API rate limit. WARNING: Abusing this feature may violate the service provider's policy and may lead to getting your account(s) blocked.
+migrate.github_token_desc = You can put one or more tokens here, separated by commas, to make migrating faster by circumventing the GitHub API rate limit. WARNING: Abusing this feature may violate the service provider's policy and may lead to getting your account(s) blocked.
migrate.clone_local_path = or a local server path
migrate.permission_denied = You are not allowed to import local repositories.
-migrate.permission_denied_blocked = You cannot import from disallowed hosts, please ask the admin to check ALLOWED_DOMAINS/ALLOW_LOCALNETWORKS/BLOCKED_DOMAINS settings.
+migrate.permission_denied_blocked = You cannot import from disallowed hosts. Please ask the admin to check ALLOWED_DOMAINS/ALLOW_LOCALNETWORKS/BLOCKED_DOMAINS settings.
migrate.invalid_local_path = "The local path is invalid. It doesn't exist or is not a directory."
migrate.invalid_lfs_endpoint = The LFS endpoint is not valid.
migrate.failed = Migration failed: %v
@@ -1205,7 +1205,7 @@ migrate.migrate_items_options = Access Token is required to migrate additional i
migrated_from = Migrated from <a href="%[1]s">%[2]s</a>
migrated_from_fake = Migrated From %[1]s
migrate.migrate = Migrate From %s
-migrate.migrating = Migrating from <b>%s</b> ...
+migrate.migrating = Migrating from <b>%s</b>…
migrate.migrating_failed = Migrating from <b>%s</b> failed.
migrate.migrating_failed.error = Failed to migrate: %s
migrate.migrating_failed_no_addr = Migration failed.
@@ -1254,7 +1254,7 @@ clone_this_repo = Clone this repository
cite_this_repo = Cite this repository
create_new_repo_command = Creating a new repository on the command line
push_exist_repo = Pushing an existing repository from the command line
-empty_message = This repository does not contain any content.
+empty_message = This repository does not have any content.
broken_message = The Git data underlying this repository cannot be read. Contact the administrator of this instance or delete this repository.
no_branch = This repository doesn't have any branches.
@@ -1273,7 +1273,7 @@ projects = Projects
packages = Packages
actions = Actions
labels = Labels
-org_labels_desc = Organization level labels that can be used with <strong>all repositories</strong> under this organization
+org_labels_desc = Organization-level labels that can be used with <strong>all repositories</strong> under this organization
org_labels_desc_manage = manage
milestone = Milestone
@@ -1370,17 +1370,17 @@ editor.new_branch_name_desc = New branch name…
editor.cancel = Cancel
editor.filename_cannot_be_empty = The filename cannot be empty.
editor.filename_is_invalid = The filename is invalid: "%s".
-editor.commit_email = Commit email
-editor.invalid_commit_email = The email for the commit is invalid.
+editor.commit_email = Commit email address
+editor.invalid_commit_email = The email address for the commit is invalid.
editor.branch_does_not_exist = Branch "%s" does not exist in this repository.
editor.branch_already_exists = Branch "%s" already exists in this repository.
editor.directory_is_a_file = Directory name "%s" is already used as a filename in this repository.
-editor.file_is_a_symlink = `"%s" is a symbolic link. Symbolic links cannot be edited in the web editor`
+editor.file_is_a_symlink = `"%s" is a symbolic link. Symbolic links cannot be edited in the web editor.`
editor.filename_is_a_directory = Filename "%s" is already used as a directory name in this repository.
editor.file_modifying_no_longer_exists = The file being modified, "%s", no longer exists in this repository.
editor.file_changed_while_editing = The file contents have changed since you started editing. <a target="_blank" rel="noopener noreferrer" href="%s">Click here</a> to see them or <strong>Commit Changes again</strong> to overwrite them.
editor.file_already_exists = A file named "%s" already exists in this repository.
-editor.commit_id_not_matching = The Commit ID does not match the ID when you began editing. Commit into a patch branch and then merge.
+editor.commit_id_not_matching = The Commit ID does not match the ID when you began editing. Commit into a patch branch and then merge.
editor.push_out_of_date = The push appears to be out of date.
editor.commit_empty_file_header = Commit an empty file
editor.commit_empty_file_text = The file you're about to commit is empty. Proceed?
@@ -1406,7 +1406,7 @@ editor.fork_create_description = You cannot edit this repository directly. Inste
editor.fork_edit_description = You cannot edit this repository directly. The changes will be written to your fork <b>%s</b>, so you can create a pull request.
editor.fork_not_editable = You have forked this repository but your fork is not editable.
editor.fork_failed_to_push_branch = Failed to push branch %s to your repository.
-editor.fork_branch_exists = Branch "%s" already exists in your fork, please choose a new branch name.
+editor.fork_branch_exists = Branch "%s" already exists in your fork. Please choose a new branch name.
commits.desc = Browse source code change history.
commits.commits = Commits
@@ -1508,7 +1508,7 @@ issues.new.clear_assignees = Clear assignees
issues.new.no_assignees = No Assignees
issues.new.no_reviewers = No Reviewers
issues.new.blocked_user = Cannot create issue because you are blocked by the repository owner.
-issues.edit.already_changed = Unable to save changes to the issue. It appears the content has already been changed by another user. Please refresh the page and try editing again to avoid overwriting their changes
+issues.edit.already_changed = Unable to save changes to the issue. It appears the content has already been changed by another user. Please refresh the page and try editing again to avoid overwriting their changes.
issues.edit.blocked_user = Cannot edit content because you are blocked by the poster or repository owner.
issues.choose.get_started = Get Started
issues.choose.open_external_link = Open
@@ -1580,7 +1580,7 @@ issues.filter_type.reviewed_by_you = Reviewed by you
issues.filter_sort = Sort
issues.filter_sort.latest = Newest
issues.filter_sort.oldest = Oldest
-issues.filter_sort.recentupdate = Recently updated
+issues.filter_sort.recentupdate = Most recently updated
issues.filter_sort.leastupdate = Least recently updated
issues.filter_sort.mostcomment = Most commented
issues.filter_sort.leastcomment = Least commented
@@ -1780,9 +1780,9 @@ issues.dependency.pr_closing_blockedby = Closing this pull request is blocked by
issues.dependency.issue_closing_blockedby = Closing this issue is blocked by the following issues
issues.dependency.issue_close_blocks = This issue blocks closing of the following issues
issues.dependency.pr_close_blocks = This pull request blocks closing of the following issues
-issues.dependency.issue_close_blocked = You need to close all issues blocking this issue before you can close it.
+issues.dependency.issue_close_blocked = You need to close all issues that are blocking this issue before you can close it.
issues.dependency.issue_batch_close_blocked = "Cannot batch close issues that you choose, because issue #%d still has open dependencies"
-issues.dependency.pr_close_blocked = You need to close all issues blocking this pull request before you can merge it.
+issues.dependency.pr_close_blocked = You need to close all issues that are blocking this pull request before you can merge it.
issues.dependency.blocks_short = Blocks
issues.dependency.blocked_by_short = Depends on
issues.dependency.remove_header = Remove Dependency
@@ -1793,13 +1793,13 @@ issues.dependency.add_error_same_issue = You cannot make an issue depend on itse
issues.dependency.add_error_dep_issue_not_exist = Dependent issue does not exist.
issues.dependency.add_error_dep_not_exist = Dependency does not exist.
issues.dependency.add_error_dep_exists = Dependency already exists.
-issues.dependency.add_error_cannot_create_circular = You cannot create a dependency with two issues blocking each other.
+issues.dependency.add_error_cannot_create_circular = You cannot create a dependency with two issues that block each other.
issues.dependency.add_error_dep_not_same_repo = Both issues must be in the same repository.
issues.review.self.approval = You cannot approve your own pull request.
issues.review.self.rejection = You cannot request changes on your own pull request.
issues.review.approve = "approved these changes %s"
issues.review.comment = "reviewed %s"
-issues.review.dismissed = "dismissed %s’s review %s"
+issues.review.dismissed = "dismissed %s's review %s"
issues.review.dismissed_label = Dismissed
issues.review.left_comment = left a comment
issues.review.content.empty = You need to leave a comment indicating the requested change(s).
@@ -1807,7 +1807,7 @@ issues.review.reject = "requested changes %s"
issues.review.wait = "was requested for review %s"
issues.review.add_review_request = "requested review from %s %s"
issues.review.remove_review_request = "removed review request for %s %s"
-issues.review.remove_review_request_self = "refused to review %s"
+issues.review.remove_review_request_self = "declined to review %s"
issues.review.pending = Pending
issues.review.pending.tooltip = This comment is not currently visible to other users. To submit your pending comments, select "%s" -> "%s/%s/%s" at the top of the page.
issues.review.review = Review
@@ -1829,7 +1829,7 @@ issues.review.requested = Review pending
issues.review.rejected = Changes requested
issues.review.stale = Updated since approval
issues.review.unofficial = Uncounted approval
-issues.assignee.error = Not all assignees was added due to an unexpected error.
+issues.assignee.error = Not all assignees were added, due to an unexpected error.
issues.reference_issue.body = Body
issues.content_history.deleted = deleted
issues.content_history.edited = edited
@@ -1846,7 +1846,7 @@ pulls.desc = Enable pull requests and code reviews.
pulls.new = New Pull Request
pulls.new.blocked_user = Cannot create pull request because you are blocked by the repository owner.
pulls.new.must_collaborator = You must be a collaborator to create pull request.
-pulls.edit.already_changed = Unable to save changes to the pull request. It appears the content has already been changed by another user. Please refresh the page and try editing again to avoid overwriting their changes
+pulls.edit.already_changed = Unable to save changes to the pull request. It appears the content has already been changed by another user. Please refresh the page and try editing again to avoid overwriting their changes.
pulls.view = View Pull Request
pulls.compare_changes = New Pull Request
pulls.allow_edits_from_maintainers = Allow edits from maintainers
@@ -1867,7 +1867,7 @@ pulls.show_all_commits = Show all commits
pulls.show_changes_since_your_last_review = Show changes since your last review
pulls.showing_only_single_commit = Showing only changes of commit %[1]s
pulls.showing_specified_commit_range = Showing only changes between %[1]s..%[2]s
-pulls.select_commit_hold_shift_for_range = Select commit. Hold shift + click to select a range
+pulls.select_commit_hold_shift_for_range = Select commit. Hold Shift and click to select a range.
pulls.review_only_possible_for_full_diff = Review is only possible when viewing the full diff
pulls.filter_changes_by_commit = Filter by commit
pulls.nothing_to_compare = These branches are equal. There is no need to create a pull request.
@@ -1896,7 +1896,7 @@ pulls.add_prefix = Add <strong>%s</strong> prefix
pulls.remove_prefix = Remove <strong>%s</strong> prefix
pulls.data_broken = This pull request is broken due to missing fork information.
pulls.files_conflicted = This pull request has changes conflicting with the target branch.
-pulls.is_checking = Checking for merge conflicts ...
+pulls.is_checking = Checking for merge conflicts…
pulls.is_ancestor = "This branch is already included in the target branch. There is nothing to merge."
pulls.is_empty = "The changes on this branch are already on the target branch. This will be an empty commit."
pulls.required_status_check_failed = Some required checks were not successful.
@@ -1920,16 +1920,16 @@ pulls.reject_count_1 = "%d change request"
pulls.reject_count_n = "%d change requests"
pulls.waiting_count_1 = "%d waiting review"
pulls.waiting_count_n = "%d waiting reviews"
-pulls.wrong_commit_id = "commit id must be a commit id on the target branch"
+pulls.wrong_commit_id = "commit ID must be a commit ID on the target branch"
pulls.no_merge_desc = This pull request cannot be merged because all repository merge options are disabled.
pulls.no_merge_helper = Enable merge options in the repository settings or merge the pull request manually.
pulls.no_merge_wip = This pull request cannot be merged because it is marked as being a work in progress.
-pulls.no_merge_not_ready = This pull request is not ready to be merged, check review status and status checks.
+pulls.no_merge_not_ready = This pull request is not ready to be merged. Check review status and status checks.
pulls.no_merge_access = You are not authorized to merge this pull request.
pulls.merge_pull_request = Create merge commit
-pulls.rebase_merge_pull_request = Rebase then fast-forward
-pulls.rebase_merge_commit_pull_request = Rebase then create merge commit
+pulls.rebase_merge_pull_request = Rebase, then fast-forward
+pulls.rebase_merge_commit_pull_request = Rebase, then create merge commit
pulls.squash_merge_pull_request = Create squash commit
pulls.fast_forward_only_merge_pull_request = Fast-forward only
pulls.merge_manually = Manually merged
@@ -1937,17 +1937,17 @@ pulls.merge_commit_id = The merge commit ID
pulls.require_signed_wont_sign = The branch requires signed commits but this merge will not be signed
pulls.invalid_merge_option = You cannot use this merge option for this pull request.
-pulls.merge_conflict = Merge Failed: There was a conflict whilst merging. Hint: Try a different strategy
+pulls.merge_conflict = Merge Failed: There was a conflict while merging. Hint: Try a different strategy.
pulls.merge_conflict_summary = Error Message
-pulls.rebase_conflict = Merge Failed: There was a conflict whilst rebasing commit: %[1]s. Hint: Try a different strategy
+pulls.rebase_conflict = Merge Failed: There was a conflict while rebasing commit: %[1]s. Hint: Try a different strategy.
pulls.rebase_conflict_summary = Error Message
-pulls.unrelated_histories = Merge Failed: The merge head and base do not share a common history. Hint: Try a different strategy
-pulls.merge_out_of_date = Merge Failed: Whilst generating the merge, the base was updated. Hint: Try again.
-pulls.head_out_of_date = Merge Failed: Whilst generating the merge, the head was updated. Hint: Try again.
-pulls.has_merged = Failed: The pull request has been merged, you cannot merge again or change the target branch.
+pulls.unrelated_histories = Merge Failed: The merge head and base do not share a common history. Hint: Try a different strategy.
+pulls.merge_out_of_date = Merge Failed: While generating the merge, the base was updated. Hint: Try again.
+pulls.head_out_of_date = Merge Failed: While generating the merge, the head was updated. Hint: Try again.
+pulls.has_merged = Failed: The pull request has been merged. You cannot merge again or change the target branch.
pulls.push_rejected = Push Failed: The push was rejected. Review the Git Hooks for this repository.
pulls.push_rejected_summary = Full Rejection Message
-pulls.push_rejected_no_message = Push Failed: The push was rejected but there was no remote message. Review the Git Hooks for this repository
+pulls.push_rejected_no_message = Push Failed: The push was rejected but there was no remote message. Review the Git Hooks for this repository.
pulls.open_unmerged_pull_exists = `You cannot perform a reopen operation because there is a pending pull request (#%d) with identical properties.`
pulls.status_checking = Some checks are pending
pulls.status_checks_success = All checks were successful
@@ -1973,7 +1973,7 @@ pulls.cmd_instruction_merge_title = Merge
pulls.cmd_instruction_merge_desc = Merge the changes and update on Gitea.
pulls.cmd_instruction_merge_warning = Warning: This operation cannot merge pull request because "autodetect manual merge" is not enabled.
pulls.clear_merge_message = Clear merge message
-pulls.clear_merge_message_hint = Clearing the merge message will only remove the commit message content and keep generated git trailers such as "Co-Authored-By …".
+pulls.clear_merge_message_hint = Clearing the merge message will only remove the commit message content and keep generated git trailers such as "Co-Authored-By…".
pulls.auto_merge_button_when_succeed = (When checks succeed)
pulls.auto_merge_when_succeed = Auto merge when all checks succeed
@@ -2039,7 +2039,7 @@ signing.wont_sign.nokey = There is no key available to sign this commit.
signing.wont_sign.never = Commits are never signed.
signing.wont_sign.always = Commits are always signed.
signing.wont_sign.pubkey = The commit will not be signed because you do not have a public key associated with your account.
-signing.wont_sign.twofa = You must have two factor authentication enabled to have commits signed.
+signing.wont_sign.twofa = You must have two-factor authentication enabled to have commits signed.
signing.wont_sign.parentsigned = The commit will not be signed as the parent commit is not signed.
signing.wont_sign.basesigned = The merge will not be signed as the base commit is not signed.
signing.wont_sign.headsigned = The merge will not be signed as the head commit is not signed.
@@ -2153,13 +2153,13 @@ contributors.contribution_type.additions = Additions
contributors.contribution_type.deletions = Deletions
settings = Settings
-settings.desc = Settings is where you can manage the settings for the repository
+settings.desc = Settings is where you can manage the settings for the repository.
settings.options = Repository
settings.public_access = Public Access
settings.public_access_desc = Configure public visitor's access permissions to override the defaults of this repository.
settings.public_access.docs.not_set = Not Set: no extra public access permission. The visitor's permission follows the repository's visibility and member permissions.
settings.public_access.docs.anonymous_read = Anonymous Read: users who are not logged in can access the unit with read permission.
-settings.public_access.docs.everyone_read = Everyone Read: all logged-in users can access the unit with read permission. Read permission of issues/pull-requests units also means users can create new issues/pull-requests.
+settings.public_access.docs.everyone_read = Everyone Read: all logged-in users can access the unit with read permission. Read permission of issue/pull-request units also means users can create new issues/pull requests.
settings.public_access.docs.everyone_write = Everyone Write: all logged-in users have write permission to the unit. Only Wiki unit supports this permission.
settings.collaboration = Collaborators
settings.collaboration.admin = Administrator
@@ -2177,7 +2177,7 @@ settings.mirror_settings.docs.disabled_pull_mirror.instructions = Set up your pr
settings.mirror_settings.docs.disabled_push_mirror.instructions = Set up your project to automatically pull commits, tags and branches from another repository.
settings.mirror_settings.docs.disabled_push_mirror.pull_mirror_warning = Right now, this can only be done in the "New Migration" menu. For more information, please consult:
settings.mirror_settings.docs.disabled_push_mirror.info = Push mirrors have been disabled by your site administrator.
-settings.mirror_settings.docs.no_new_mirrors = Your repository is mirroring changes to or from another repository. Please keep in mind that you can't create any new mirrors at this time.
+settings.mirror_settings.docs.no_new_mirrors = Your repository is mirroring changes to or from another repository. Please keep in mind that you currently can't create any new mirrors.
settings.mirror_settings.docs.can_still_use = Although you can't modify existing mirrors or create new ones, you may still use your existing mirror.
settings.mirror_settings.docs.pull_mirror_instructions = To set up a pull mirror, please consult:
settings.mirror_settings.docs.more_information_if_disabled = You can find out more about push and pull mirrors here:
@@ -2252,7 +2252,7 @@ settings.admin_indexer_commit_sha = Last Indexed SHA
settings.admin_indexer_unindexed = Unindexed
settings.reindex_button = Add to Reindex Queue
settings.reindex_requested=Reindex Requested
-settings.admin_enable_close_issues_via_commit_in_any_branch = Close an issue via a commit made in a non default branch
+settings.admin_enable_close_issues_via_commit_in_any_branch = Close an issue via a commit made in a non-default branch
settings.danger_zone = Danger Zone
settings.new_owner_has_same_repo = The new owner already has a repository with same name. Please choose another name.
settings.convert = Convert to Regular Repository
@@ -2274,7 +2274,7 @@ settings.transfer_abort_invalid = You cannot cancel a non existent repository tr
settings.transfer_abort_success = The repository transfer to %s was successfully canceled.
settings.transfer_desc = Transfer this repository to a user or to an organization for which you have administrator rights.
settings.transfer_form_title = Enter the repository name as confirmation:
-settings.transfer_in_progress = There is currently an ongoing transfer. Please cancel it if you will like to transfer this repository to another user.
+settings.transfer_in_progress = There is currently an ongoing transfer. Please cancel it if you would like to transfer this repository to another user.
settings.transfer_notices_1 = - You will lose access to the repository if you transfer it to an individual user.
settings.transfer_notices_2 = - You will keep access to the repository if you transfer it to an organization that you (co-)own.
settings.transfer_notices_3 = - If the repository is private and is transferred to an individual user, this action makes sure that the user does have at least read permission (and changes permissions if necessary).
@@ -2289,13 +2289,13 @@ settings.trust_model.default = Default Trust Model
settings.trust_model.default.desc= Use the default repository trust model for this installation.
settings.trust_model.collaborator = Collaborator
settings.trust_model.collaborator.long = Collaborator: Trust signatures by collaborators
-settings.trust_model.collaborator.desc = Valid signatures by collaborators of this repository will be marked "trusted" - (whether they match the committer or not). Otherwise, valid signatures will be marked "untrusted" if the signature matches the committer and "unmatched" if not.
+settings.trust_model.collaborator.desc = Valid signatures by collaborators of this repository will be marked "trusted", whether they match the committer or not. Otherwise, valid signatures will be marked "untrusted" if the signature matches the committer and "unmatched" if not.
settings.trust_model.committer = Committer
-settings.trust_model.committer.long = Committer: Trust signatures that match committers (This matches GitHub and will force Gitea signed commits to have Gitea as the committer)
-settings.trust_model.committer.desc = Valid signatures will only be marked "trusted" if they match the committer, otherwise they will be marked "unmatched". This forces Gitea to be the committer on signed commits with the actual committer marked as Co-authored-by: and Co-committed-by: trailer in the commit. The default Gitea key must match a User in the database.
+settings.trust_model.committer.long = Committer: Trust signatures that match committers. This matches GitHub's behavior and will force commits signed by Gitea to have Gitea as the committer.
+settings.trust_model.committer.desc = Valid signatures will only be marked "trusted" if they match the committer, otherwise they will be marked "unmatched". This forces Gitea to be the committer on signed commits, with the actual committer marked as Co-authored-by: and Co-committed-by: trailer in the commit. The default Gitea key must match a user in the database.
settings.trust_model.collaboratorcommitter = Collaborator+Committer
settings.trust_model.collaboratorcommitter.long = Collaborator+Committer: Trust signatures by collaborators which match the committer
-settings.trust_model.collaboratorcommitter.desc = Valid signatures by collaborators of this repository will be marked "trusted" if they match the committer. Otherwise, valid signatures will be marked "untrusted" if the signature matches the committer and "unmatched" otherwise. This will force Gitea to be marked as the committer on signed commits with the actual committer marked as Co-Authored-By: and Co-Committed-By: trailer in the commit. The default Gitea key must match a User in the database.
+settings.trust_model.collaboratorcommitter.desc = Valid signatures by collaborators of this repository will be marked "trusted" if they match the committer. Otherwise, valid signatures will be marked "untrusted" if the signature matches the committer and "unmatched" otherwise. This will force Gitea to be marked as the committer on signed commits, with the actual committer marked as Co-Authored-By: and Co-Committed-By: trailer in the commit. The default Gitea key must match a user in the database.
settings.wiki_delete = Delete Wiki Data
settings.wiki_delete_desc = Deleting repository wiki data is permanent and cannot be undone.
settings.wiki_delete_notices_1 = - This will permanently delete and disable the repository wiki for %s.
@@ -2304,7 +2304,7 @@ settings.wiki_deletion_success = The repository wiki data has been deleted.
settings.delete = Delete This Repository
settings.delete_desc = Deleting a repository is permanent and cannot be undone.
settings.delete_notices_1 = - This operation <strong>CANNOT</strong> be undone.
-settings.delete_notices_2 = - This operation will permanently delete the <strong>%s</strong> repository including code, issues, comments, wiki data and collaborator settings.
+settings.delete_notices_2 = - This operation will permanently delete the <strong>%s</strong> repository, including code, issues, comments, wiki data and collaborator settings.
settings.delete_notices_fork_1 = - Forks of this repository will become independent after deletion.
settings.deletion_success = The repository has been deleted.
settings.update_settings_success = The repository settings have been updated.
@@ -2326,8 +2326,8 @@ settings.team_not_in_organization = The team is not in the same organization as
settings.teams = Teams
settings.add_team = Add Team
settings.add_team_duplicate = Team already has the repository
-settings.add_team_success = The team now have access to the repository.
-settings.change_team_permission_tip = Team's permission is set on the team setting page and can't be changed per repository
+settings.add_team_success = The team now has access to the repository.
+settings.change_team_permission_tip = Team's permission is set on the team settings page and can't be changed per repository
settings.delete_team_tip = This team has access to all repositories and can't be removed
settings.remove_team_success = The team's access to the repository has been removed.
settings.add_webhook = Add Webhook
@@ -2592,7 +2592,7 @@ settings.archive.tagsettings_unavailable = Tag settings are not available if the
settings.archive.mirrors_unavailable = Mirrors are not available if the repo is archived.
settings.unarchive.button = Unarchive repo
settings.unarchive.header = Unarchive this repo
-settings.unarchive.text = Unarchiving the repo will restore its ability to receive commits and pushes, as well as new issues and pull-requests.
+settings.unarchive.text = Unarchiving the repo will restore its ability to receive commits and pushes, as well as new issues and pull requests.
settings.unarchive.success = The repo was successfully unarchived.
settings.unarchive.error = An error occurred while trying to unarchive the repo. See the log for more details.
settings.update_avatar_success = The repository avatar has been updated.
@@ -2610,11 +2610,11 @@ settings.lfs_invalid_locking_path=Invalid path: %s
settings.lfs_invalid_lock_directory=Cannot lock directory: %s
settings.lfs_lock_already_exists=Lock already exists: %s
settings.lfs_lock=Lock
-settings.lfs_lock_path=Filepath to lock...
+settings.lfs_lock_path=Filepath to lock…
settings.lfs_locks_no_locks=No Locks
settings.lfs_lock_file_no_exist=Locked file does not exist in default branch
settings.lfs_force_unlock=Force Unlock
-settings.lfs_pointers.found=Found %d blob pointer(s) - %d associated, %d unassociated (%d missing from store)
+settings.lfs_pointers.found=Found %d blob pointer(s) — %d associated, %d unassociated (%d missing from store)
settings.lfs_pointers.sha=Blob SHA
settings.lfs_pointers.oid=OID
settings.lfs_pointers.inRepo=In Repo
@@ -2772,7 +2772,7 @@ branch.new_branch_from = Create new branch from "%s"
branch.renamed = Branch %s was renamed to %s.
branch.rename_default_or_protected_branch_error = Only admins can rename default or protected branches.
branch.rename_protected_branch_failed = This branch is protected by glob-based protection rules.
-branch.commits_divergence_from = Commits divergence: %[1]d behind and %[2]d ahead of %[3]s
+branch.commits_divergence_from = Commit divergence: %[1]d behind and %[2]d ahead of %[3]s
branch.commits_no_divergence = The same as branch %[1]s
tag.create_tag = Create tag %s
@@ -2797,7 +2797,7 @@ error.csv.invalid_field_count = Can't render this file because it has a wrong nu
error.broken_git_hook = Git hooks of this repository seem to be broken. Please follow the <a target="_blank" rel="noreferrer" href="%s">documentation</a> to fix them, then push some commits to refresh the status.
[graphs]
-component_loading = Loading %s...
+component_loading = Loading %s…
component_loading_failed = Could not load %s
component_loading_info = This might take a bit…
component_failed_to_load = An unexpected error happened.
@@ -2836,7 +2836,7 @@ form.create_org_not_allowed = You are not allowed to create an organization.
settings = Settings
settings.options = Organization
settings.full_name = Full Name
-settings.email = Contact Email
+settings.email = Contact Email Address
settings.website = Website
settings.location = Location
settings.permission = Permissions
@@ -2853,10 +2853,10 @@ settings.update_setting_success = Organization settings have been updated.
settings.rename = Rename Organization
settings.rename_desc = Changing the organization name will also change your organization's URL and free the old name.
-settings.rename_success = Organization %[1]s have been renamed to %[2]s successfully.
-settings.rename_no_change = Organization name is no change.
+settings.rename_success = Organization %[1]s has been renamed to %[2]s successfully.
+settings.rename_no_change = Organization name is not changed.
settings.rename_new_org_name = New Organization Name
-settings.rename_failed = Rename Organization failed because of internal error
+settings.rename_failed = Renaming organization failed because of an internal error
settings.rename_notices_1 = This operation <strong>CANNOT</strong> be undone.
settings.rename_notices_2 = The old name will redirect until it is claimed.
@@ -2866,11 +2866,11 @@ settings.delete_account = Delete This Organization
settings.delete_prompt = The organization will be permanently removed. This <strong>CANNOT</strong> be undone!
settings.name_confirm = Enter the organization name as confirmation:
settings.delete_notices_1 = This operation <strong>CANNOT</strong> be undone.
-settings.delete_notices_2 = This operation will permanently delete all the <strong>repositories</strong> of <strong>%s</strong> including code, issues, comments, wiki data and collaborator settings.
+settings.delete_notices_2 = This operation will permanently delete all the <strong>repositories</strong> of <strong>%s</strong>, including code, issues, comments, wiki data and collaborator settings.
settings.delete_notices_3 = This operation will permanently delete all the <strong>packages</strong> of <strong>%s</strong>.
settings.delete_notices_4 = This operation will permanently delete all the <strong>projects</strong> of <strong>%s</strong>.
settings.confirm_delete_account = Confirm Deletion
-settings.delete_failed = Delete Organization failed due to an internal error
+settings.delete_failed = Deleting organization failed due to an internal error
settings.delete_successful = Organization <b>%s</b> has been deleted successfully.
settings.hooks_desc = Add webhooks which will be triggered for <strong>all repositories</strong> under this organization.
@@ -2927,7 +2927,7 @@ teams.remove_all_repos_title = Remove all team repositories
teams.remove_all_repos_desc = This will remove all repositories from the team.
teams.add_all_repos_title = Add all repositories
teams.add_all_repos_desc = This will add all the organization's repositories to the team.
-teams.add_nonexistent_repo = "The repository you're trying to add doesn't exist, please create it first."
+teams.add_nonexistent_repo = "The repository you're trying to add doesn't exist. Please create it first."
teams.add_duplicate_users = User is already a team member.
teams.repos.none = No repositories could be accessed by this team.
teams.members.none = No members on this team.
@@ -2968,7 +2968,7 @@ repositories = Repositories
hooks = Webhooks
integrations = Integrations
authentication = Authentication Sources
-emails = User Emails
+emails = User Email Addresses
config = Configuration
config_summary = Summary
config_settings = Settings
@@ -3000,11 +3000,11 @@ dashboard.cron.cancelled=Cron: %[1]s canceled: %[3]s
dashboard.cron.error=Error in Cron: %s: %[3]s
dashboard.cron.finished=Cron: %[1]s has finished
dashboard.delete_inactive_accounts = Delete all unactivated accounts
-dashboard.delete_inactive_accounts.started = Delete all unactivated accounts task started.
+dashboard.delete_inactive_accounts.started = Task to delete all unactivated accounts started
dashboard.delete_repo_archives = "Delete all repositories' archives (ZIP, TAR.GZ, etc..)"
-dashboard.delete_repo_archives.started = Delete all repository archives task started.
+dashboard.delete_repo_archives.started = Task to delete all repository archives started
dashboard.delete_missing_repos = Delete all repositories missing their Git files
-dashboard.delete_missing_repos.started = Delete all repositories missing their Git files task started.
+dashboard.delete_missing_repos.started = Task to delete all repositories missing their Git files started
dashboard.delete_generated_repository_avatars = Delete generated repository avatars
dashboard.sync_repo_branches = Sync missed branches from git data to databases
dashboard.sync_repo_tags = Sync tags from git data to database
@@ -3012,12 +3012,12 @@ dashboard.update_mirrors = Update Mirrors
dashboard.repo_health_check = Health check all repositories
dashboard.check_repo_stats = Check all repository statistics
dashboard.archive_cleanup = Delete old repository archives
-dashboard.deleted_branches_cleanup = Clean-up deleted branches
+dashboard.deleted_branches_cleanup = Clean up deleted branches
dashboard.update_migration_poster_id = Update migration poster IDs
-dashboard.git_gc_repos = Garbage collect all repositories
-dashboard.resync_all_sshkeys = Update the '.ssh/authorized_keys' file with Gitea SSH keys.
-dashboard.resync_all_sshprincipals = Update the '.ssh/authorized_principals' file with Gitea SSH principals.
-dashboard.resync_all_hooks = Resynchronize pre-receive, update and post-receive hooks of all repositories.
+dashboard.git_gc_repos = Garbage-collect all repositories
+dashboard.resync_all_sshkeys = Update the '.ssh/authorized_keys' file with Gitea SSH keys
+dashboard.resync_all_sshprincipals = Update the '.ssh/authorized_principals' file with Gitea SSH principals
+dashboard.resync_all_hooks = Resynchronize pre-receive, update and post-receive hooks of all repositories
dashboard.reinit_missing_repos = Reinitialize all missing Git repositories for which records exist
dashboard.sync_external_users = Synchronize external user data
dashboard.cleanup_hook_task_table = Clean up hook_task table
@@ -3053,10 +3053,10 @@ dashboard.total_gc_pause = Total GC Pause
dashboard.last_gc_pause = Last GC Pause
dashboard.gc_times = GC Times
dashboard.delete_old_actions = Delete all old activities from database
-dashboard.delete_old_actions.started = Delete all old activities from database started.
+dashboard.delete_old_actions.started = Deletion of all old activities from database started
dashboard.update_checker = Update checker
dashboard.delete_old_system_notices = Delete all old system notices from database
-dashboard.gc_lfs = Garbage collect LFS meta objects
+dashboard.gc_lfs = Garbage-collect LFS meta objects
dashboard.stop_zombie_tasks = Stop actions zombie tasks
dashboard.stop_endless_tasks = Stop actions endless tasks
dashboard.cancel_abandoned_jobs = Cancel actions abandoned jobs
@@ -3080,7 +3080,7 @@ users.2fa = 2FA
users.repos = Repos
users.created = Created
users.last_login = Last Sign-In
-users.never_login = Never Signed-In
+users.never_login = Never Signed In
users.send_register_notify = Send User Registration Notification
users.new_success = The user account "%s" has been created.
users.edit = Edit
@@ -3107,7 +3107,7 @@ users.still_own_repo = This user still owns one or more repositories. Delete or
users.still_has_org = This user is a member of an organization. Remove the user from any organizations first.
users.purge = Purge User
users.purge_help = Forcibly delete user and any repositories, organizations, and packages owned by the user. All comments will be deleted too.
-users.still_own_packages = This user still owns one or more packages, delete these packages first.
+users.still_own_packages = This user still owns one or more packages. Delete these packages first.
users.deletion_success = The user account has been deleted.
users.reset_2fa = Reset 2FA
users.list_status_filter.menu_text = Filter
@@ -3127,11 +3127,11 @@ users.details = User Details
emails.email_manage_panel = User Email Management
emails.primary = Primary
emails.activated = Activated
-emails.filter_sort.email = Email
-emails.filter_sort.email_reverse = Email (reverse)
-emails.filter_sort.name = User Name
-emails.filter_sort.name_reverse = User Name (reverse)
-emails.updated = Email updated
+emails.filter_sort.email = Email address
+emails.filter_sort.email_reverse = Email address (reverse)
+emails.filter_sort.name = Username
+emails.filter_sort.name_reverse = Username (reverse)
+emails.updated = Email address updated
emails.not_updated = Failed to update the requested email address: %v
emails.duplicate_active = This email address is already active for a different user.
emails.change_email_header = Update Email Properties
@@ -3139,7 +3139,7 @@ emails.change_email_text = Are you sure you want to update this email address?
emails.delete = Delete Email
emails.delete_desc = Are you sure you want to delete this email address?
emails.deletion_success = The email address has been deleted.
-emails.delete_primary_email_error = You can not delete the primary email.
+emails.delete_primary_email_error = You cannot delete the primary email address.
orgs.org_manage_panel = Organization Management
orgs.name = Name
@@ -3253,29 +3253,29 @@ auths.oauth2_required_claim_name_helper = Set this name to restrict login from t
auths.oauth2_required_claim_value = Required Claim Value
auths.oauth2_required_claim_value_helper = Set this value to restrict login from this source to users with a claim with this name and value
auths.oauth2_group_claim_name = Claim name providing group names for this source. (Optional)
-auths.oauth2_full_name_claim_name = Full Name Claim Name. (Optional, if set, the user's full name will always be synchronized with this claim)
+auths.oauth2_full_name_claim_name = Full Name Claim Name. (Optional; if set, the user's full name will always be synchronized with this claim)
auths.oauth2_ssh_public_key_claim_name = SSH Public Key Claim Name
-auths.oauth2_admin_group = Group Claim value for administrator users. (Optional - requires claim name above)
-auths.oauth2_restricted_group = Group Claim value for restricted users. (Optional - requires claim name above)
-auths.oauth2_map_group_to_team = Map claimed groups to Organization teams. (Optional - requires claim name above)
+auths.oauth2_admin_group = Group Claim value for administrator users. (Optional — requires claim name above)
+auths.oauth2_restricted_group = Group Claim value for restricted users. (Optional — requires claim name above)
+auths.oauth2_map_group_to_team = Map claimed groups to Organization teams. (Optional — requires claim name above)
auths.oauth2_map_group_to_team_removal = Remove users from synchronized teams if user does not belong to corresponding group.
auths.enable_auto_register = Enable Auto Registration
auths.sspi_auto_create_users = Automatically create users
-auths.sspi_auto_create_users_helper = Allow SSPI auth method to automatically create new accounts for users that login for the first time
+auths.sspi_auto_create_users_helper = Allow SSPI auth method to automatically create new accounts for users that log in for the first time
auths.sspi_auto_activate_users = Automatically activate users
auths.sspi_auto_activate_users_helper = Allow SSPI auth method to automatically activate new users
auths.sspi_strip_domain_names = Remove domain names from usernames
-auths.sspi_strip_domain_names_helper = If checked, domain names will be removed from logon names (eg. "DOMAIN\user" and "user@example.org" both will become just "user").
+auths.sspi_strip_domain_names_helper = If checked, domain names will be removed from logon names (e.g. "DOMAIN\user" and "user@example.org" both will become just "user").
auths.sspi_separator_replacement = Separator to use instead of \, / and @
-auths.sspi_separator_replacement_helper = The character to use to replace the separators of down-level logon names (eg. the \ in "DOMAIN\user") and user principal names (eg. the @ in "user@example.org").
+auths.sspi_separator_replacement_helper = The character to use to replace the separators of down-level logon names (e.g. the \ in "DOMAIN\user") and user principal names (e.g. the @ in "user@example.org").
auths.sspi_default_language = Default user language
-auths.sspi_default_language_helper = Default language for users automatically created by SSPI auth method. Leave empty if you prefer language to be automatically detected.
+auths.sspi_default_language_helper = Default language for users automatically created by SSPI auth method. Leave empty if you prefer the language to be automatically detected.
auths.tips = Tips
auths.tips.oauth2.general = OAuth2 Authentication
auths.tips.oauth2.general.tip = When registering a new OAuth2 authentication, the callback/redirect URL should be:
auths.tip.oauth2_provider = OAuth2 Provider
auths.tip.bitbucket = Register a new OAuth consumer on %s and add the permission 'Account' - 'Read'
-auths.tip.nextcloud = Register a new OAuth consumer on your instance using the following menu "Settings -> Security -> OAuth 2.0 client"
+auths.tip.nextcloud = Register a new OAuth consumer on your instance by selecting "Settings -> Security -> OAuth 2.0 client" in the menu
auths.tip.dropbox = Create a new application at %s
auths.tip.facebook = Register a new application at %s and add the product "Facebook Login"
auths.tip.github = Register a new OAuth application on %s
@@ -3385,7 +3385,7 @@ config.mailer_sendmail_path = Sendmail Path
config.mailer_sendmail_args = Extra Arguments to Sendmail
config.mailer_sendmail_timeout = Sendmail Timeout
config.mailer_use_dummy = Dummy
-config.test_email_placeholder = Email (e.g. test@example.com)
+config.test_email_placeholder = Email Address (e.g. test@example.com)
config.send_test_mail = Send Testing Email
config.send_test_mail_submit = Send
config.test_mail_failed = Failed to send a testing email to "%s": %v
@@ -3474,7 +3474,7 @@ monitor.queue.numberinqueue = Number in Queue
monitor.queue.review_add = Review / Add Workers
monitor.queue.settings.title = Pool Settings
monitor.queue.settings.desc = Pools dynamically grow in response to their worker queue blocking.
-monitor.queue.settings.maxnumberworkers = Max Number of workers
+monitor.queue.settings.maxnumberworkers = Max number of workers
monitor.queue.settings.maxnumberworkers.placeholder = Currently %[1]d
monitor.queue.settings.maxnumberworkers.error = Max number of workers must be a number
monitor.queue.settings.submit = Update Settings
@@ -3500,10 +3500,10 @@ notices.delete_success = The system notices have been deleted.
self_check.no_problem_found = No problem found yet.
self_check.startup_warnings = Startup warnings:
self_check.database_collation_mismatch = Expect database to use collation: %s
-self_check.database_collation_case_insensitive = Database is using a collation %s, which is an insensitive collation. Although Gitea could work with it, there might be some rare cases which don't work as expected.
-self_check.database_inconsistent_collation_columns = Database is using collation %s, but these columns are using mismatched collations. It might cause some unexpected problems.
-self_check.database_fix_mysql = For MySQL/MariaDB users, you could use the "gitea doctor convert" command to fix the collation problems, or you could also fix the problem by "ALTER ... COLLATE ..." SQLs manually.
-self_check.database_fix_mssql = For MSSQL users, you could only fix the problem by "ALTER ... COLLATE ..." SQLs manually at the moment.
+self_check.database_collation_case_insensitive = Database is using collation %s, which is a case-insensitive collation. Although Gitea could work with it, there might be some rare cases which don't work as expected.
+self_check.database_inconsistent_collation_columns = Database is using collation %s, but these columns are using mismatched collations. This might cause some unexpected problems.
+self_check.database_fix_mysql = For MySQL/MariaDB users, you could use the "gitea doctor convert" command to fix the collation problems, or you could also fix the problem manually with "ALTER ... COLLATE ..." SQL queries.
+self_check.database_fix_mssql = For MSSQL users, you could only fix the problem manually with "ALTER ... COLLATE ..." SQL queries at the moment.
self_check.location_origin_mismatch = Current URL (%[1]s) doesn't match the URL seen by Gitea (%[2]s). If you are using a reverse proxy, please make sure the "Host" and "X-Forwarded-Proto" headers are set correctly.
[action]
@@ -3587,8 +3587,8 @@ error.no_committer_account = No account linked to committer's email address
error.no_gpg_keys_found = "No known key found for this signature in database"
error.not_signed_commit = "Not a signed commit"
error.failed_retrieval_gpg_keys = "Failed to retrieve any key attached to the committer's account"
-error.probable_bad_signature = "WARNING! Although there is a key with this ID in the database it does not verify this commit! This commit is SUSPICIOUS."
-error.probable_bad_default_signature = "WARNING! Although the default key has this ID it does not verify this commit! This commit is SUSPICIOUS."
+error.probable_bad_signature = "WARNING! Although there is a key with this ID in the database, it does not verify this commit! This commit is SUSPICIOUS."
+error.probable_bad_default_signature = "WARNING! Although the default key has this ID, it does not verify this commit! This commit is SUSPICIOUS."
[units]
unit = Unit
@@ -3627,7 +3627,7 @@ versions.view_all = View all
dependency.id = ID
dependency.version = Version
search_in_external_registry = Search in %s
-alpine.registry = Setup this registry by adding the url in your <code>/etc/apk/repositories</code> file:
+alpine.registry = Set up this registry by adding the URL in your <code>/etc/apk/repositories</code> file:
alpine.registry.key = Download the registry public RSA key into the <code>/etc/apk/keys/</code> folder to verify the index signature:
alpine.registry.info = Choose $branch and $repository from the list below.
alpine.install = To install the package, run the following command:
@@ -3640,18 +3640,18 @@ arch.install = Sync package with pacman:
arch.repository = Repository Info
arch.repository.repositories = Repositories
arch.repository.architectures = Architectures
-cargo.registry = Setup this registry in the Cargo configuration file (for example <code>~/.cargo/config.toml</code>):
+cargo.registry = Set up this registry in the Cargo configuration file (for example <code>~/.cargo/config.toml</code>):
cargo.install = To install the package using Cargo, run the following command:
-chef.registry = Setup this registry in your <code>~/.chef/config.rb</code> file:
+chef.registry = Set up this registry in your <code>~/.chef/config.rb</code> file:
chef.install = To install the package, run the following command:
-composer.registry = Setup this registry in your <code>~/.composer/config.json</code> file:
+composer.registry = Set up this registry in your <code>~/.composer/config.json</code> file:
composer.install = To install the package using Composer, run the following command:
composer.dependencies = Dependencies
composer.dependencies.development = Development Dependencies
conan.details.repository = Repository
-conan.registry = Setup this registry from the command line:
+conan.registry = Set up this registry from the command line:
conan.install = To install the package using Conan, run the following command:
-conda.registry = Setup this registry as a Conda repository in your <code>.condarc</code> file:
+conda.registry = Set up this registry as a Conda repository in your <code>.condarc</code> file:
conda.install = To install the package using Conda, run the following command:
container.details.type = Image Type
container.details.platform = Platform
@@ -3663,9 +3663,9 @@ container.layers = Image Layers
container.labels = Labels
container.labels.key = Key
container.labels.value = Value
-cran.registry = Setup this registry in your <code>Rprofile.site</code> file:
+cran.registry = Set up this registry in your <code>Rprofile.site</code> file:
cran.install = To install the package, run the following command:
-debian.registry = Setup this registry from the command line:
+debian.registry = Set up this registry from the command line:
debian.registry.info = Choose $distribution and $component from the list below.
debian.install = To install the package, run the following command:
debian.repository = Repository Info
@@ -3674,16 +3674,16 @@ debian.repository.components = Components
debian.repository.architectures = Architectures
generic.download = Download package from the command line:
go.install = Install the package from the command line:
-helm.registry = Setup this registry from the command line:
+helm.registry = Set up this registry from the command line:
helm.install = To install the package, run the following command:
-maven.registry = Setup this registry in your project <code>pom.xml</code> file:
-maven.install = To use the package include the following in the <code>dependencies</code> block in the <code>pom.xml</code> file:
+maven.registry = Set up this registry in your project <code>pom.xml</code> file:
+maven.install = To use the package, include the following in the <code>dependencies</code> block in the <code>pom.xml</code> file:
maven.install2 = Run via command line:
maven.download = To download the dependency, run via command line:
-nuget.registry = Setup this registry from the command line:
+nuget.registry = Set up this registry from the command line:
nuget.install = To install the package using NuGet, run the following command:
nuget.dependency.framework = Target Framework
-npm.registry = Setup this registry in your project <code>.npmrc</code> file:
+npm.registry = Set up this registry in your project <code>.npmrc</code> file:
npm.install = To install the package using npm, run the following command:
npm.install2 = or add it to the package.json file:
npm.dependencies = Dependencies
@@ -3695,7 +3695,7 @@ npm.details.tag = Tag
pub.install = To install the package using Dart, run the following command:
pypi.requires = Requires Python
pypi.install = To install the package using pip, run the following command:
-rpm.registry = Setup this registry from the command line:
+rpm.registry = Set up this registry from the command line:
rpm.distros.redhat = on RedHat based distributions
rpm.distros.suse = on SUSE based distributions
rpm.install = To install the package, run the following command:
@@ -3708,7 +3708,7 @@ rubygems.dependencies.runtime = Runtime Dependencies
rubygems.dependencies.development = Development Dependencies
rubygems.required.ruby = Requires Ruby version
rubygems.required.rubygems = Requires RubyGem version
-swift.registry = Setup this registry from the command line:
+swift.registry = Set up this registry from the command line:
swift.install = Add the package in your <code>Package.swift</code> file:
swift.install2 = and run the following command:
vagrant.install = To add a Vagrant box, run the following command:
diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini
index a47083b45e..ba822f5cc1 100644
--- a/options/locale/locale_zh-CN.ini
+++ b/options/locale/locale_zh-CN.ini
@@ -130,6 +130,7 @@ unpin=å–æ¶ˆç½®é¡¶
artifacts=产物
expired=已过期
+confirm_delete_artifact=您确定è¦åˆ é™¤äº§ç‰©ã€Œ%sã€å—?
archived=已归档
@@ -459,6 +460,7 @@ oauth_signin_submit=绑定账å·
oauth.signin.error.general=å¤„ç†æŽˆæƒè¯·æ±‚时出错:%s。如果此错误ä»ç„¶å­˜åœ¨ï¼Œè¯·ä¸Žç«™ç‚¹ç®¡ç†å‘˜è”系。
oauth.signin.error.access_denied=授æƒè¯·æ±‚被拒ç»ã€‚
oauth.signin.error.temporarily_unavailable=授æƒå¤±è´¥ï¼Œå› ä¸ºè®¤è¯æœåŠ¡å™¨æš‚æ—¶ä¸å¯ç”¨ã€‚请ç¨åŽå†è¯•。
+oauth_callback_unable_auto_reg=自动注册已å¯ç”¨ï¼Œä½† OAuth2 æä¾›å•† %[1]s 返回缺失的字段:%[2]sï¼Œæ— æ³•è‡ªåŠ¨åˆ›å»ºå¸æˆ·ï¼Œè¯·åˆ›å»ºæˆ–é“¾æŽ¥åˆ°ä¸€ä¸ªå¸æˆ·ï¼Œæˆ–è”系站点管ç†å‘˜ã€‚
openid_connect_submit=连接
openid_connect_title=è¿žæŽ¥åˆ°çŽ°æœ‰çš„å¸æˆ·
openid_connect_desc=所选的 OpenID URI 未知。在这里关è”ä¸€ä¸ªæ–°å¸æˆ·ã€‚
@@ -499,6 +501,7 @@ activate_email.text=请在 <b>%s</b> æ—¶é—´å†…ï¼Œç‚¹å‡»ä»¥ä¸‹é“¾æŽ¥ï¼Œä»¥éªŒè¯æ
register_notify=欢迎æ¥åˆ° %s
register_notify.title=%[1]s,欢迎æ¥åˆ° %[2]s
+register_notify.text_1=这是您的 %s 注册确认邮件 ï¼
register_notify.text_3=如果此账户已为您创建,请先 <a href="%s">设置您的密ç </a>。
reset_password=æ¢å¤æ‚¨çš„账户
@@ -723,6 +726,7 @@ webauthn=两步验è¯ï¼ˆå®‰å…¨å¯†é’¥ï¼‰
public_profile=公开信æ¯
biography_placeholder=å‘Šè¯‰æˆ‘ä»¬ä¸€ç‚¹æ‚¨è‡ªå·±ï¼ (您å¯ä»¥ä½¿ç”¨ Markdown)
location_placeholder=与他人分享您的大概ä½ç½®
+profile_desc=控制您的个人资料对其他用户的显示方å¼ã€‚您的主邮箱地å€å°†ç”¨äºŽé€šçŸ¥ã€å¯†ç æ¢å¤å’ŒåŸºäºŽç½‘页的 Git æ“作。
password_username_disabled=您ä¸è¢«å…许更改您的用户å。更多详情请è”系您的系统管ç†å‘˜ã€‚
password_full_name_disabled=您ä¸è¢«å…许更改您的全å。请è”系您的站点管ç†å‘˜äº†è§£æ›´å¤šè¯¦æƒ…。
full_name=自定义åç§°
@@ -801,6 +805,7 @@ activations_pending=等待激活
can_not_add_email_activations_pending=有一个待处ç†çš„æ¿€æ´»è¯·æ±‚,请ç¨ç­‰å‡ åˆ†é’ŸåŽå†å°è¯•添加新的邮箱地å€ã€‚
delete_email=移除
email_deletion=移除邮箱地å€
+email_deletion_desc=邮箱地å€å’Œç›¸å…³ä¿¡æ¯å°†ä¼šè¢«åˆ é™¤ã€‚使用此邮箱地å€å‘é€çš„Gitæäº¤å°†ä¼šä¿ç•™ï¼Œç»§ç»­ï¼Ÿ
email_deletion_success=您的邮箱地å€å·²ç§»é™¤ã€‚
theme_update_success=您的主题已更新。
theme_update_error=所选主题ä¸å­˜åœ¨ã€‚
@@ -986,6 +991,7 @@ webauthn_alternative_tip=您å¯èƒ½æƒ³è¦é…ç½®é¢å¤–çš„èº«ä»½éªŒè¯æ–¹æ³•。
manage_account_links=管ç†ç»‘定过的账å·
manage_account_links_desc=è¿™äº›å¤–éƒ¨å¸æˆ·å·²ç»ç»‘定到您的 Gitea 叿ˆ·ã€‚
+account_links_not_available=当剿²¡æœ‰å¤–éƒ¨å¸æˆ·é“¾æŽ¥åˆ°æ‚¨çš„ Gitea 叿ˆ·ã€‚
link_account=链接账户
remove_account_link=删除已绑定的账å·
remove_account_link_desc=åˆ é™¤å·²ç»‘å®šå¸æˆ·å°†åŠé”€å…¶å¯¹æ‚¨çš„ Gitea 叿ˆ·çš„访问æƒé™ã€‚继续?
@@ -1008,6 +1014,8 @@ email_notifications.onmention=仅被æåŠæ—¶é€šçŸ¥
email_notifications.disable=åœç”¨é‚®ä»¶é€šçŸ¥
email_notifications.submit=设置邮件通知
email_notifications.andyourown=仅与您相关的通知
+email_notifications.actions.desc=设置了 <a target="_blank" href="%s">Gitea 工作æµ</a> 的仓库中工作æµè¿è¡Œçš„通知。
+email_notifications.actions.failure_only=仅在工作æµè¿è¡Œå¤±è´¥æ—¶é€šçŸ¥
visibility=用户å¯è§æ€§
visibility.public=公开
@@ -1022,6 +1030,8 @@ new_repo_helper=代ç ä»“库包å«äº†æ‰€æœ‰çš„项目文件,包括版本历å²è
owner=拥有者
owner_helper=由于最大仓库数é‡é™åˆ¶ï¼Œä¸€äº›ç»„织å¯èƒ½ä¸ä¼šæ˜¾ç¤ºåœ¨ä¸‹æ‹‰åˆ—表中。
repo_name=仓库åç§°
+repo_name_profile_public_hint=.profile 是一个特殊的仓库,您å¯ä»¥ä½¿ç”¨å®ƒå°† README.md 添加到您的公共组织资料中,任何人都å¯ä»¥çœ‹åˆ°ã€‚请确ä¿å®ƒæ˜¯å…¬å¼€çš„,并使用个人资料目录中的 README 对其进行åˆå§‹åŒ–以开始使用。
+repo_name_profile_private_hint=.profile-private 是一个特殊的仓库,您å¯ä»¥ä½¿ç”¨å®ƒå‘您的组织æˆå‘˜ä¸ªäººèµ„料添加 README.md,仅对组织æˆå‘˜å¯è§ã€‚请确ä¿å®ƒæ˜¯ç§æœ‰çš„,并使用个人资料目录中的 README 对其进行åˆå§‹åŒ–以开始使用。
repo_name_helper=ç†æƒ³çš„仓库åç§°åº”ç”±ç®€çŸ­ã€æœ‰æ„义和独特的关键è¯ç»„æˆã€‚「.profileã€å’Œã€Œ.profile-privateã€å¯ç”¨äºŽä¸ºç”¨æˆ·/组织添加 README.md。
repo_size=仓库大å°
template=模æ¿
@@ -1380,6 +1390,8 @@ editor.failed_to_commit=æäº¤æ›´æ”¹å¤±è´¥ã€‚
editor.failed_to_commit_summary=错误信æ¯ï¼š
editor.fork_create=æ´¾ç”Ÿä»“åº“ä»¥è¯·æ±‚å˜æ›´
+editor.fork_create_description=您ä¸èƒ½ç›´æŽ¥ç¼–辑此仓库。您å¯ä»¥æ´¾ç”Ÿæ­¤ä»“库,进行编辑并创建一个åˆå¹¶è¯·æ±‚。
+editor.fork_edit_description=您ä¸èƒ½ç›´æŽ¥ç¼–辑此仓库。 更改将写入您的派生仓库 <b>%s</b>,以便您å¯ä»¥åˆ›å»ºä¸€ä¸ªåˆå¹¶è¯·æ±‚。
editor.fork_not_editable=æ‚¨å·²ç»æ´¾ç”Ÿäº†æ­¤ä»“库,但您的派生是ä¸å¯ç¼–辑的。
editor.fork_failed_to_push_branch=推é€åˆ†æ”¯ %s 到仓库失败。
editor.fork_branch_exists=分支「%sã€å·²å­˜åœ¨äºŽæ‚¨çš„æ´¾ç”Ÿä»“库中,请选择一个新的分支å称。
@@ -2795,6 +2807,7 @@ team_permission_desc=æƒé™
team_unit_desc=å…许访问仓库å•å…ƒ
team_unit_disabled=(å·²ç¦ç”¨)
+form.name_been_taken=组织å称「%sã€å·²ç»è¢«å ç”¨ã€‚
form.name_reserved=组织å称「%sã€æ˜¯ä¿ç•™çš„。
form.name_pattern_not_allowed=组织å中ä¸å…许使用「%sã€æ ¼å¼ã€‚
form.create_org_not_allowed=此账å·ç¦æ­¢åˆ›å»ºç»„织
@@ -2836,6 +2849,7 @@ settings.delete_notices_2=æ­¤æ“作将永久删除 <strong>%s</strong> 的所有
settings.delete_notices_3=æ­¤æ“作将永久删除 <strong>%s</strong> 的所有 <strong>软件包</strong>。
settings.delete_notices_4=æ­¤æ“作将永久删除 <strong>%s</strong> 的所有 <strong>项目</strong>。
settings.confirm_delete_account=确认删除组织
+settings.delete_failed=由于内部错误,删除组织失败
settings.delete_successful=组织 <b>%s</b> å·²æˆåŠŸåˆ é™¤ã€‚
settings.hooks_desc=在此处添加的 Web é’©å­å°†ä¼šåº”用到该组织下的 <strong>所有仓库</strong>。
@@ -2985,6 +2999,8 @@ dashboard.resync_all_sshprincipals=使用 Gitea 的 SSH 规则更新「.ssh/auth
dashboard.resync_all_hooks=釿–°åŒæ­¥æ‰€æœ‰ä»“库的 pre-receiveã€update å’Œ post-receive é’©å­
dashboard.reinit_missing_repos=釿–°åˆå§‹åŒ–所有丢失的 Git 仓库存在的记录
dashboard.sync_external_users=åŒæ­¥å¤–部用户数æ®
+dashboard.cleanup_hook_task_table=æ¸…ç† hook_task 表
+dashboard.cleanup_actions=清ç†è¿‡æœŸçš„工作æµèµ„æº
dashboard.server_uptime=æœåŠ¡è¿è¡Œæ—¶é—´
dashboard.current_goroutine=å½“å‰ Goroutines æ•°é‡
dashboard.current_memory_usage=当å‰å†…存使用é‡
@@ -3215,6 +3231,8 @@ auths.oauth2_required_claim_name_helper=设置此åç§°ï¼Œåªæœ‰å…·æœ‰æ­¤åç§°ç
auths.oauth2_required_claim_value=必须填写 Claim 声明的值
auths.oauth2_required_claim_value_helper=è®¾ç½®æ­¤å€¼ï¼Œåªæœ‰æ‹¥æœ‰å¯¹åº”的声明(Claim)的å称和值的用户æ‰è¢«å…许从此æºç™»å½•
auths.oauth2_group_claim_name=用于æä¾›ç”¨æˆ·ç»„åç§°çš„ Claim 声明å称。(å¯é€‰)
+auths.oauth2_full_name_claim_name=å…¨å声明å称。(å¯é€‰ï¼Œå¦‚果设置,用户的全åå°†å§‹ç»ˆä¸Žæ­¤å£°æ˜ŽåŒæ­¥ï¼‰
+auths.oauth2_ssh_public_key_claim_name=SSH 公钥声明åç§°
auths.oauth2_admin_group=管ç†å‘˜ç”¨æˆ·ç»„çš„ Claim 声明值。(å¯é€‰ - 需è¦ä¸Šé¢çš„声明åç§°)
auths.oauth2_restricted_group=å—é™ç”¨æˆ·ç»„çš„ Claim 声明值。(å¯é€‰ - 需è¦ä¸Šé¢çš„声明åç§°)
auths.oauth2_map_group_to_team=映射声明的组到组织团队。(å¯é€‰ - è¦æ±‚在上é¢å¡«å†™å£°æ˜Žçš„å字)
@@ -3690,6 +3708,7 @@ owner.settings.cargo.initialize.success=Cargo ç´¢å¼•å·²ç»æˆåŠŸåˆ›å»ºã€‚
owner.settings.cargo.rebuild=é‡å»ºç´¢å¼•
owner.settings.cargo.rebuild.description=如果索引与存储的 Cargo 包ä¸åŒæ­¥ï¼Œé‡å»ºå¯èƒ½ä¼šæœ‰ç”¨ã€‚
owner.settings.cargo.rebuild.error=无法é‡å»º Cargo 索引: %v
+owner.settings.cargo.rebuild.success=Cargo 索引已æˆåŠŸé‡å»ºã€‚
owner.settings.cleanuprules.title=ç®¡ç†æ¸…ç†è§„则
owner.settings.cleanuprules.add=添加清ç†è§„则
owner.settings.cleanuprules.edit=编辑清ç†è§„则
diff --git a/poetry.toml b/poetry.toml
deleted file mode 100644
index 6eda9f8eff..0000000000
--- a/poetry.toml
+++ /dev/null
@@ -1,3 +0,0 @@
-[virtualenvs]
-in-project = true
-options.no-pip = true
diff --git a/routers/api/v1/repo/action.go b/routers/api/v1/repo/action.go
index ef0c5cc199..99eef2f53b 100644
--- a/routers/api/v1/repo/action.go
+++ b/routers/api/v1/repo/action.go
@@ -46,7 +46,7 @@ func (Action) ListActionsSecrets(ctx *context.APIContext) {
// parameters:
// - name: owner
// in: path
- // description: owner of the repository
+ // description: owner of the repo
// type: string
// required: true
// - name: repo
@@ -216,7 +216,7 @@ func (Action) GetVariable(ctx *context.APIContext) {
// parameters:
// - name: owner
// in: path
- // description: name of the owner
+ // description: owner of the repo
// type: string
// required: true
// - name: repo
@@ -270,7 +270,7 @@ func (Action) DeleteVariable(ctx *context.APIContext) {
// parameters:
// - name: owner
// in: path
- // description: name of the owner
+ // description: owner of the repo
// type: string
// required: true
// - name: repo
@@ -319,7 +319,7 @@ func (Action) CreateVariable(ctx *context.APIContext) {
// parameters:
// - name: owner
// in: path
- // description: name of the owner
+ // description: owner of the repo
// type: string
// required: true
// - name: repo
@@ -386,7 +386,7 @@ func (Action) UpdateVariable(ctx *context.APIContext) {
// parameters:
// - name: owner
// in: path
- // description: name of the owner
+ // description: owner of the repo
// type: string
// required: true
// - name: repo
@@ -458,7 +458,7 @@ func (Action) ListVariables(ctx *context.APIContext) {
// parameters:
// - name: owner
// in: path
- // description: name of the owner
+ // description: owner of the repo
// type: string
// required: true
// - name: repo
@@ -660,7 +660,7 @@ func (Action) ListWorkflowJobs(ctx *context.APIContext) {
// parameters:
// - name: owner
// in: path
- // description: name of the owner
+ // description: owner of the repo
// type: string
// required: true
// - name: repo
@@ -704,7 +704,7 @@ func (Action) ListWorkflowRuns(ctx *context.APIContext) {
// parameters:
// - name: owner
// in: path
- // description: name of the owner
+ // description: owner of the repo
// type: string
// required: true
// - name: repo
@@ -1110,7 +1110,7 @@ func GetWorkflowRun(ctx *context.APIContext) {
// parameters:
// - name: owner
// in: path
- // description: name of the owner
+ // description: owner of the repo
// type: string
// required: true
// - name: repo
@@ -1156,7 +1156,7 @@ func ListWorkflowRunJobs(ctx *context.APIContext) {
// parameters:
// - name: owner
// in: path
- // description: name of the owner
+ // description: owner of the repo
// type: string
// required: true
// - name: repo
@@ -1215,7 +1215,7 @@ func GetWorkflowJob(ctx *context.APIContext) {
// parameters:
// - name: owner
// in: path
- // description: name of the owner
+ // description: owner of the repo
// type: string
// required: true
// - name: repo
@@ -1261,7 +1261,7 @@ func GetArtifactsOfRun(ctx *context.APIContext) {
// parameters:
// - name: owner
// in: path
- // description: name of the owner
+ // description: owner of the repo
// type: string
// required: true
// - name: repo
@@ -1330,7 +1330,7 @@ func DeleteActionRun(ctx *context.APIContext) {
// parameters:
// - name: owner
// in: path
- // description: name of the owner
+ // description: owner of the repo
// type: string
// required: true
// - name: repo
@@ -1382,7 +1382,7 @@ func GetArtifacts(ctx *context.APIContext) {
// parameters:
// - name: owner
// in: path
- // description: name of the owner
+ // description: owner of the repo
// type: string
// required: true
// - name: repo
@@ -1443,7 +1443,7 @@ func GetArtifact(ctx *context.APIContext) {
// parameters:
// - name: owner
// in: path
- // description: name of the owner
+ // description: owner of the repo
// type: string
// required: true
// - name: repo
@@ -1492,7 +1492,7 @@ func DeleteArtifact(ctx *context.APIContext) {
// parameters:
// - name: owner
// in: path
- // description: name of the owner
+ // description: owner of the repo
// type: string
// required: true
// - name: repo
@@ -1559,7 +1559,7 @@ func DownloadArtifact(ctx *context.APIContext) {
// parameters:
// - name: owner
// in: path
- // description: name of the owner
+ // description: owner of the repo
// type: string
// required: true
// - name: repo
diff --git a/routers/api/v1/repo/actions_run.go b/routers/api/v1/repo/actions_run.go
index c6d18af6aa..a12a6fdd6d 100644
--- a/routers/api/v1/repo/actions_run.go
+++ b/routers/api/v1/repo/actions_run.go
@@ -21,7 +21,7 @@ func DownloadActionsRunJobLogs(ctx *context.APIContext) {
// parameters:
// - name: owner
// in: path
- // description: name of the owner
+ // description: owner of the repo
// type: string
// required: true
// - name: repo
diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go
index e05b9b165c..09729200d5 100644
--- a/routers/api/v1/repo/pull.go
+++ b/routers/api/v1/repo/pull.go
@@ -52,7 +52,7 @@ func ListPullRequests(ctx *context.APIContext) {
// parameters:
// - name: owner
// in: path
- // description: Owner of the repo
+ // description: owner of the repo
// type: string
// required: true
// - name: repo
diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go
index 292b267c01..4b88ed0b78 100644
--- a/routers/api/v1/repo/repo.go
+++ b/routers/api/v1/repo/repo.go
@@ -329,7 +329,7 @@ func Generate(ctx *context.APIContext) {
// parameters:
// - name: template_owner
// in: path
- // description: name of the template repository owner
+ // description: owner of the template repository
// type: string
// required: true
// - name: template_repo
diff --git a/services/asymkey/deploy_key.go b/services/asymkey/deploy_key.go
index 9e5a6d6292..04023f9ffb 100644
--- a/services/asymkey/deploy_key.go
+++ b/services/asymkey/deploy_key.go
@@ -49,28 +49,21 @@ func deleteDeployKeyFromDB(ctx context.Context, key *asymkey_model.DeployKey) er
// DeleteDeployKey deletes deploy key from its repository authorized_keys file if needed.
// Permissions check should be done outside.
func DeleteDeployKey(ctx context.Context, repo *repo_model.Repository, id int64) error {
- dbCtx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- key, err := asymkey_model.GetDeployKeyByID(ctx, id)
- if err != nil {
- if asymkey_model.IsErrDeployKeyNotExist(err) {
- return nil
+ if err := db.WithTx(ctx, func(ctx context.Context) error {
+ key, err := asymkey_model.GetDeployKeyByID(ctx, id)
+ if err != nil {
+ if asymkey_model.IsErrDeployKeyNotExist(err) {
+ return nil
+ }
+ return fmt.Errorf("GetDeployKeyByID: %w", err)
}
- return fmt.Errorf("GetDeployKeyByID: %w", err)
- }
- if key.RepoID != repo.ID {
- return fmt.Errorf("deploy key %d does not belong to repository %d", id, repo.ID)
- }
+ if key.RepoID != repo.ID {
+ return fmt.Errorf("deploy key %d does not belong to repository %d", id, repo.ID)
+ }
- if err := deleteDeployKeyFromDB(dbCtx, key); err != nil {
- return err
- }
- if err := committer.Commit(); err != nil {
+ return deleteDeployKeyFromDB(ctx, key)
+ }); err != nil {
return err
}
diff --git a/services/asymkey/ssh_key.go b/services/asymkey/ssh_key.go
index da57059d4b..01fa7ff15f 100644
--- a/services/asymkey/ssh_key.go
+++ b/services/asymkey/ssh_key.go
@@ -27,20 +27,9 @@ func DeletePublicKey(ctx context.Context, doer *user_model.User, id int64) (err
}
}
- dbCtx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- if _, err = db.DeleteByID[asymkey_model.PublicKey](dbCtx, id); err != nil {
- return err
- }
-
- if err = committer.Commit(); err != nil {
+ if _, err = db.DeleteByID[asymkey_model.PublicKey](ctx, id); err != nil {
return err
}
- committer.Close()
if key.Type == asymkey_model.KeyTypePrincipal {
return RewriteAllPrincipalKeys(ctx)
diff --git a/services/asymkey/ssh_key_principals.go b/services/asymkey/ssh_key_principals.go
index 5ed5cfa782..6493c1cc51 100644
--- a/services/asymkey/ssh_key_principals.go
+++ b/services/asymkey/ssh_key_principals.go
@@ -14,24 +14,6 @@ import (
// AddPrincipalKey adds new principal to database and authorized_principals file.
func AddPrincipalKey(ctx context.Context, ownerID int64, content string, authSourceID int64) (*asymkey_model.PublicKey, error) {
- dbCtx, committer, err := db.TxContext(ctx)
- if err != nil {
- return nil, err
- }
- defer committer.Close()
-
- // Principals cannot be duplicated.
- has, err := db.GetEngine(dbCtx).
- Where("content = ? AND type = ?", content, asymkey_model.KeyTypePrincipal).
- Get(new(asymkey_model.PublicKey))
- if err != nil {
- return nil, err
- } else if has {
- return nil, asymkey_model.ErrKeyAlreadyExist{
- Content: content,
- }
- }
-
key := &asymkey_model.PublicKey{
OwnerID: ownerID,
Name: content,
@@ -40,15 +22,27 @@ func AddPrincipalKey(ctx context.Context, ownerID int64, content string, authSou
Type: asymkey_model.KeyTypePrincipal,
LoginSourceID: authSourceID,
}
- if err = db.Insert(dbCtx, key); err != nil {
- return nil, fmt.Errorf("addKey: %w", err)
- }
- if err = committer.Commit(); err != nil {
+ if err := db.WithTx(ctx, func(ctx context.Context) error {
+ // Principals cannot be duplicated.
+ has, err := db.GetEngine(ctx).
+ Where("content = ? AND type = ?", content, asymkey_model.KeyTypePrincipal).
+ Get(new(asymkey_model.PublicKey))
+ if err != nil {
+ return err
+ } else if has {
+ return asymkey_model.ErrKeyAlreadyExist{
+ Content: content,
+ }
+ }
+
+ if err = db.Insert(ctx, key); err != nil {
+ return fmt.Errorf("addKey: %w", err)
+ }
+ return nil
+ }); err != nil {
return nil, err
}
- committer.Close()
-
return key, RewriteAllPrincipalKeys(ctx)
}
diff --git a/services/issue/label.go b/services/issue/label.go
index 6b8070d8aa..e30983df37 100644
--- a/services/issue/label.go
+++ b/services/issue/label.go
@@ -46,32 +46,24 @@ func AddLabels(ctx context.Context, issue *issues_model.Issue, doer *user_model.
// RemoveLabel removes a label from issue by given ID.
func RemoveLabel(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, label *issues_model.Label) error {
- dbCtx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- if err := issue.LoadRepo(dbCtx); err != nil {
- return err
- }
-
- perm, err := access_model.GetUserRepoPermission(dbCtx, issue.Repo, doer)
- if err != nil {
- return err
- }
- if !perm.CanWriteIssuesOrPulls(issue.IsPull) {
- if label.OrgID > 0 {
- return issues_model.ErrOrgLabelNotExist{}
+ if err := db.WithTx(ctx, func(ctx context.Context) error {
+ if err := issue.LoadRepo(ctx); err != nil {
+ return err
}
- return issues_model.ErrRepoLabelNotExist{}
- }
- if err := issues_model.DeleteIssueLabel(dbCtx, issue, label, doer); err != nil {
- return err
- }
+ perm, err := access_model.GetUserRepoPermission(ctx, issue.Repo, doer)
+ if err != nil {
+ return err
+ }
+ if !perm.CanWriteIssuesOrPulls(issue.IsPull) {
+ if label.OrgID > 0 {
+ return issues_model.ErrOrgLabelNotExist{}
+ }
+ return issues_model.ErrRepoLabelNotExist{}
+ }
- if err := committer.Commit(); err != nil {
+ return issues_model.DeleteIssueLabel(ctx, issue, label, doer)
+ }); err != nil {
return err
}
diff --git a/services/issue/milestone.go b/services/issue/milestone.go
index afca70794d..05aefad752 100644
--- a/services/issue/milestone.go
+++ b/services/issue/milestone.go
@@ -69,21 +69,12 @@ func changeMilestoneAssign(ctx context.Context, doer *user_model.User, issue *is
// ChangeMilestoneAssign changes assignment of milestone for issue.
func ChangeMilestoneAssign(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, oldMilestoneID int64) (err error) {
- dbCtx, committer, err := db.TxContext(ctx)
- if err != nil {
+ if err := db.WithTx(ctx, func(dbCtx context.Context) error {
+ return changeMilestoneAssign(dbCtx, doer, issue, oldMilestoneID)
+ }); err != nil {
return err
}
- defer committer.Close()
-
- if err = changeMilestoneAssign(dbCtx, doer, issue, oldMilestoneID); err != nil {
- return err
- }
-
- if err = committer.Commit(); err != nil {
- return fmt.Errorf("Commit: %w", err)
- }
notify_service.IssueChangeMilestone(ctx, doer, issue, oldMilestoneID)
-
return nil
}
diff --git a/services/issue/status.go b/services/issue/status.go
index f9d7dca841..fa59df93ba 100644
--- a/services/issue/status.go
+++ b/services/issue/status.go
@@ -15,30 +15,24 @@ import (
// CloseIssue close an issue.
func CloseIssue(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, commitID string) error {
- dbCtx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- comment, err := issues_model.CloseIssue(dbCtx, issue, doer)
- if err != nil {
- if issues_model.IsErrDependenciesLeft(err) {
- if _, err := issues_model.FinishIssueStopwatch(dbCtx, doer, issue); err != nil {
- log.Error("Unable to stop stopwatch for issue[%d]#%d: %v", issue.ID, issue.Index, err)
+ var comment *issues_model.Comment
+ if err := db.WithTx(ctx, func(ctx context.Context) error {
+ var err error
+ comment, err = issues_model.CloseIssue(ctx, issue, doer)
+ if err != nil {
+ if issues_model.IsErrDependenciesLeft(err) {
+ if _, err := issues_model.FinishIssueStopwatch(ctx, doer, issue); err != nil {
+ log.Error("Unable to stop stopwatch for issue[%d]#%d: %v", issue.ID, issue.Index, err)
+ }
}
+ return err
}
- return err
- }
- if _, err := issues_model.FinishIssueStopwatch(dbCtx, doer, issue); err != nil {
+ _, err = issues_model.FinishIssueStopwatch(ctx, doer, issue)
return err
- }
-
- if err := committer.Commit(); err != nil {
+ }); err != nil {
return err
}
- committer.Close()
notify_service.IssueChangeStatus(ctx, doer, commitID, issue, comment, true)
diff --git a/services/org/team.go b/services/org/team.go
index 6890dafd90..773bd11f49 100644
--- a/services/org/team.go
+++ b/services/org/team.go
@@ -54,39 +54,33 @@ func NewTeam(ctx context.Context, t *organization.Team) (err error) {
return organization.ErrTeamAlreadyExist{OrgID: t.OrgID, Name: t.LowerName}
}
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- if err = db.Insert(ctx, t); err != nil {
- return err
- }
-
- // insert units for team
- if len(t.Units) > 0 {
- for _, unit := range t.Units {
- unit.TeamID = t.ID
- }
- if err = db.Insert(ctx, &t.Units); err != nil {
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ if err = db.Insert(ctx, t); err != nil {
return err
}
- }
- // Add all repositories to the team if it has access to all of them.
- if t.IncludesAllRepositories {
- err = repo_service.AddAllRepositoriesToTeam(ctx, t)
- if err != nil {
- return fmt.Errorf("addAllRepositories: %w", err)
+ // insert units for team
+ if len(t.Units) > 0 {
+ for _, unit := range t.Units {
+ unit.TeamID = t.ID
+ }
+ if err = db.Insert(ctx, &t.Units); err != nil {
+ return err
+ }
+ }
+
+ // Add all repositories to the team if it has access to all of them.
+ if t.IncludesAllRepositories {
+ err = repo_service.AddAllRepositoriesToTeam(ctx, t)
+ if err != nil {
+ return fmt.Errorf("addAllRepositories: %w", err)
+ }
}
- }
- // Update organization number of teams.
- if _, err = db.Exec(ctx, "UPDATE `user` SET num_teams=num_teams+1 WHERE id = ?", t.OrgID); err != nil {
+ // Update organization number of teams.
+ _, err = db.Exec(ctx, "UPDATE `user` SET num_teams=num_teams+1 WHERE id = ?", t.OrgID)
return err
- }
- return committer.Commit()
+ })
}
// UpdateTeam updates information of team.
@@ -99,128 +93,117 @@ func UpdateTeam(ctx context.Context, t *organization.Team, authChanged, includeA
t.Description = t.Description[:255]
}
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- t.LowerName = strings.ToLower(t.Name)
- has, err := db.Exist[organization.Team](ctx, builder.Eq{
- "org_id": t.OrgID,
- "lower_name": t.LowerName,
- }.And(builder.Neq{"id": t.ID}),
- )
- if err != nil {
- return err
- } else if has {
- return organization.ErrTeamAlreadyExist{OrgID: t.OrgID, Name: t.LowerName}
- }
-
- sess := db.GetEngine(ctx)
- if _, err = sess.ID(t.ID).Cols("name", "lower_name", "description",
- "can_create_org_repo", "authorize", "includes_all_repositories").Update(t); err != nil {
- return fmt.Errorf("update: %w", err)
- }
-
- // update units for team
- if len(t.Units) > 0 {
- for _, unit := range t.Units {
- unit.TeamID = t.ID
- }
- // Delete team-unit.
- if _, err := sess.
- Where("team_id=?", t.ID).
- Delete(new(organization.TeamUnit)); err != nil {
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ t.LowerName = strings.ToLower(t.Name)
+ has, err := db.Exist[organization.Team](ctx, builder.Eq{
+ "org_id": t.OrgID,
+ "lower_name": t.LowerName,
+ }.And(builder.Neq{"id": t.ID}),
+ )
+ if err != nil {
return err
+ } else if has {
+ return organization.ErrTeamAlreadyExist{OrgID: t.OrgID, Name: t.LowerName}
}
- if _, err = sess.Cols("org_id", "team_id", "type", "access_mode").Insert(&t.Units); err != nil {
- return err
+
+ sess := db.GetEngine(ctx)
+ if _, err = sess.ID(t.ID).Cols("name", "lower_name", "description",
+ "can_create_org_repo", "authorize", "includes_all_repositories").Update(t); err != nil {
+ return fmt.Errorf("update: %w", err)
}
- }
- // Update access for team members if needed.
- if authChanged {
- repos, err := repo_model.GetTeamRepositories(ctx, &repo_model.SearchTeamRepoOptions{
- TeamID: t.ID,
- })
- if err != nil {
- return fmt.Errorf("GetTeamRepositories: %w", err)
+ // update units for team
+ if len(t.Units) > 0 {
+ for _, unit := range t.Units {
+ unit.TeamID = t.ID
+ }
+ // Delete team-unit.
+ if _, err := sess.
+ Where("team_id=?", t.ID).
+ Delete(new(organization.TeamUnit)); err != nil {
+ return err
+ }
+ if _, err = sess.Cols("org_id", "team_id", "type", "access_mode").Insert(&t.Units); err != nil {
+ return err
+ }
}
- for _, repo := range repos {
- if err = access_model.RecalculateTeamAccesses(ctx, repo, 0); err != nil {
- return fmt.Errorf("recalculateTeamAccesses: %w", err)
+ // Update access for team members if needed.
+ if authChanged {
+ repos, err := repo_model.GetTeamRepositories(ctx, &repo_model.SearchTeamRepoOptions{
+ TeamID: t.ID,
+ })
+ if err != nil {
+ return fmt.Errorf("GetTeamRepositories: %w", err)
+ }
+
+ for _, repo := range repos {
+ if err = access_model.RecalculateTeamAccesses(ctx, repo, 0); err != nil {
+ return fmt.Errorf("recalculateTeamAccesses: %w", err)
+ }
}
}
- }
- // Add all repositories to the team if it has access to all of them.
- if includeAllChanged && t.IncludesAllRepositories {
- err = repo_service.AddAllRepositoriesToTeam(ctx, t)
- if err != nil {
- return fmt.Errorf("addAllRepositories: %w", err)
+ // Add all repositories to the team if it has access to all of them.
+ if includeAllChanged && t.IncludesAllRepositories {
+ err = repo_service.AddAllRepositoriesToTeam(ctx, t)
+ if err != nil {
+ return fmt.Errorf("addAllRepositories: %w", err)
+ }
}
- }
- return committer.Commit()
+ return nil
+ })
}
// DeleteTeam deletes given team.
// It's caller's responsibility to assign organization ID.
func DeleteTeam(ctx context.Context, t *organization.Team) error {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- if err := t.LoadMembers(ctx); err != nil {
- return err
- }
-
- // update branch protections
- {
- protections := make([]*git_model.ProtectedBranch, 0, 10)
- err := db.GetEngine(ctx).In("repo_id",
- builder.Select("id").From("repository").Where(builder.Eq{"owner_id": t.OrgID})).
- Find(&protections)
- if err != nil {
- return fmt.Errorf("findProtectedBranches: %w", err)
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ if err := t.LoadMembers(ctx); err != nil {
+ return err
}
- for _, p := range protections {
- if err := git_model.RemoveTeamIDFromProtectedBranch(ctx, p, t.ID); err != nil {
- return err
+
+ // update branch protections
+ {
+ protections := make([]*git_model.ProtectedBranch, 0, 10)
+ err := db.GetEngine(ctx).In("repo_id",
+ builder.Select("id").From("repository").Where(builder.Eq{"owner_id": t.OrgID})).
+ Find(&protections)
+ if err != nil {
+ return fmt.Errorf("findProtectedBranches: %w", err)
+ }
+ for _, p := range protections {
+ if err := git_model.RemoveTeamIDFromProtectedBranch(ctx, p, t.ID); err != nil {
+ return err
+ }
}
}
- }
-
- if err := repo_service.RemoveAllRepositoriesFromTeam(ctx, t); err != nil {
- return err
- }
- if err := db.DeleteBeans(ctx,
- &organization.Team{ID: t.ID},
- &organization.TeamUser{OrgID: t.OrgID, TeamID: t.ID},
- &organization.TeamUnit{TeamID: t.ID},
- &organization.TeamInvite{TeamID: t.ID},
- &issues_model.Review{Type: issues_model.ReviewTypeRequest, ReviewerTeamID: t.ID}, // batch delete the binding relationship between team and PR (request review from team)
- ); err != nil {
- return err
- }
+ if err := repo_service.RemoveAllRepositoriesFromTeam(ctx, t); err != nil {
+ return err
+ }
- for _, tm := range t.Members {
- if err := removeInvalidOrgUser(ctx, t.OrgID, tm); err != nil {
+ if err := db.DeleteBeans(ctx,
+ &organization.Team{ID: t.ID},
+ &organization.TeamUser{OrgID: t.OrgID, TeamID: t.ID},
+ &organization.TeamUnit{TeamID: t.ID},
+ &organization.TeamInvite{TeamID: t.ID},
+ &issues_model.Review{Type: issues_model.ReviewTypeRequest, ReviewerTeamID: t.ID}, // batch delete the binding relationship between team and PR (request review from team)
+ ); err != nil {
return err
}
- }
- // Update organization number of teams.
- if _, err := db.Exec(ctx, "UPDATE `user` SET num_teams=num_teams-1 WHERE id=?", t.OrgID); err != nil {
- return err
- }
+ for _, tm := range t.Members {
+ if err := removeInvalidOrgUser(ctx, t.OrgID, tm); err != nil {
+ return err
+ }
+ }
- return committer.Commit()
+ // Update organization number of teams.
+ _, err := db.Exec(ctx, "UPDATE `user` SET num_teams=num_teams-1 WHERE id=?", t.OrgID)
+ return err
+ })
}
// AddTeamMember adds new membership of given team to given organization,
@@ -363,13 +346,7 @@ func removeInvalidOrgUser(ctx context.Context, orgID int64, user *user_model.Use
// RemoveTeamMember removes member from given team of given organization.
func RemoveTeamMember(ctx context.Context, team *organization.Team, user *user_model.User) error {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
- if err := removeTeamMember(ctx, team, user); err != nil {
- return err
- }
- return committer.Commit()
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ return removeTeamMember(ctx, team, user)
+ })
}
diff --git a/services/packages/cleanup/cleanup.go b/services/packages/cleanup/cleanup.go
index 959babe7cd..ec860db1bb 100644
--- a/services/packages/cleanup/cleanup.go
+++ b/services/packages/cleanup/cleanup.go
@@ -164,42 +164,38 @@ func ExecuteCleanupRules(ctx context.Context) error {
})
}
-func CleanupExpiredData(outerCtx context.Context, olderThan time.Duration) error {
- ctx, committer, err := db.TxContext(outerCtx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- if err := container_service.Cleanup(ctx, olderThan); err != nil {
- return err
- }
-
- ps, err := packages_model.FindUnreferencedPackages(ctx)
- if err != nil {
- return err
- }
- for _, p := range ps {
- if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypePackage, p.ID); err != nil {
+func CleanupExpiredData(ctx context.Context, olderThan time.Duration) error {
+ pbs := make([]*packages_model.PackageBlob, 0, 100)
+ if err := db.WithTx(ctx, func(ctx context.Context) error {
+ if err := container_service.Cleanup(ctx, olderThan); err != nil {
return err
}
- if err := packages_model.DeletePackageByID(ctx, p.ID); err != nil {
+
+ ps, err := packages_model.FindUnreferencedPackages(ctx)
+ if err != nil {
return err
}
- }
-
- pbs, err := packages_model.FindExpiredUnreferencedBlobs(ctx, olderThan)
- if err != nil {
- return err
- }
+ for _, p := range ps {
+ if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypePackage, p.ID); err != nil {
+ return err
+ }
+ if err := packages_model.DeletePackageByID(ctx, p.ID); err != nil {
+ return err
+ }
+ }
- for _, pb := range pbs {
- if err := packages_model.DeleteBlobByID(ctx, pb.ID); err != nil {
+ pbs, err = packages_model.FindExpiredUnreferencedBlobs(ctx, olderThan)
+ if err != nil {
return err
}
- }
- if err := committer.Commit(); err != nil {
+ for _, pb := range pbs {
+ if err := packages_model.DeleteBlobByID(ctx, pb.ID); err != nil {
+ return err
+ }
+ }
+ return nil
+ }); err != nil {
return err
}
diff --git a/services/packages/packages.go b/services/packages/packages.go
index 4b16ee7285..22b26b6563 100644
--- a/services/packages/packages.go
+++ b/services/packages/packages.go
@@ -469,24 +469,15 @@ func RemovePackageVersionByNameAndVersion(ctx context.Context, doer *user_model.
// RemovePackageVersion deletes the package version and all associated files
func RemovePackageVersion(ctx context.Context, doer *user_model.User, pv *packages_model.PackageVersion) error {
- dbCtx, committer, err := db.TxContext(ctx)
+ pd, err := packages_model.GetPackageDescriptor(ctx, pv)
if err != nil {
return err
}
- defer committer.Close()
-
- pd, err := packages_model.GetPackageDescriptor(dbCtx, pv)
- if err != nil {
- return err
- }
-
- log.Trace("Deleting package: %v", pv.ID)
- if err := DeletePackageVersionAndReferences(dbCtx, pv); err != nil {
- return err
- }
-
- if err := committer.Commit(); err != nil {
+ if err := db.WithTx(ctx, func(ctx context.Context) error {
+ log.Trace("Deleting package: %v", pv.ID)
+ return DeletePackageVersionAndReferences(ctx, pv)
+ }); err != nil {
return err
}
diff --git a/services/pull/merge.go b/services/pull/merge.go
index cd9aeb2ad1..a941c20435 100644
--- a/services/pull/merge.go
+++ b/services/pull/merge.go
@@ -687,48 +687,40 @@ func SetMerged(ctx context.Context, pr *issues_model.PullRequest, mergedCommitID
return false, fmt.Errorf("unable to merge PullRequest[%d], some required fields are empty", pr.Index)
}
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return false, err
- }
- defer committer.Close()
-
- pr.Issue = nil
- if err := pr.LoadIssue(ctx); err != nil {
- return false, err
- }
-
- if err := pr.Issue.LoadRepo(ctx); err != nil {
- return false, err
- }
+ return db.WithTx2(ctx, func(ctx context.Context) (bool, error) {
+ pr.Issue = nil
+ if err := pr.LoadIssue(ctx); err != nil {
+ return false, err
+ }
- if err := pr.Issue.Repo.LoadOwner(ctx); err != nil {
- return false, err
- }
+ if err := pr.Issue.LoadRepo(ctx); err != nil {
+ return false, err
+ }
- // Removing an auto merge pull and ignore if not exist
- if err := pull_model.DeleteScheduledAutoMerge(ctx, pr.ID); err != nil && !db.IsErrNotExist(err) {
- return false, fmt.Errorf("DeleteScheduledAutoMerge[%d]: %v", pr.ID, err)
- }
+ if err := pr.Issue.Repo.LoadOwner(ctx); err != nil {
+ return false, err
+ }
- // Set issue as closed
- if _, err := issues_model.SetIssueAsClosed(ctx, pr.Issue, pr.Merger, true); err != nil {
- return false, fmt.Errorf("ChangeIssueStatus: %w", err)
- }
+ // Removing an auto merge pull and ignore if not exist
+ if err := pull_model.DeleteScheduledAutoMerge(ctx, pr.ID); err != nil && !db.IsErrNotExist(err) {
+ return false, fmt.Errorf("DeleteScheduledAutoMerge[%d]: %v", pr.ID, err)
+ }
- // We need to save all of the data used to compute this merge as it may have already been changed by testPullRequestBranchMergeable. FIXME: need to set some state to prevent testPullRequestBranchMergeable from running whilst we are merging.
- if cnt, err := db.GetEngine(ctx).Where("id = ?", pr.ID).
- And("has_merged = ?", false).
- Cols("has_merged, status, merge_base, merged_commit_id, merger_id, merged_unix, conflicted_files").
- Update(pr); err != nil {
- return false, fmt.Errorf("failed to update pr[%d]: %w", pr.ID, err)
- } else if cnt != 1 {
- return false, issues_model.ErrIssueAlreadyChanged
- }
+ // Set issue as closed
+ if _, err := issues_model.SetIssueAsClosed(ctx, pr.Issue, pr.Merger, true); err != nil {
+ return false, fmt.Errorf("ChangeIssueStatus: %w", err)
+ }
- if err := committer.Commit(); err != nil {
- return false, err
- }
+ // We need to save all of the data used to compute this merge as it may have already been changed by testPullRequestBranchMergeable. FIXME: need to set some state to prevent testPullRequestBranchMergeable from running whilst we are merging.
+ if cnt, err := db.GetEngine(ctx).Where("id = ?", pr.ID).
+ And("has_merged = ?", false).
+ Cols("has_merged, status, merge_base, merged_commit_id, merger_id, merged_unix, conflicted_files").
+ Update(pr); err != nil {
+ return false, fmt.Errorf("failed to update pr[%d]: %w", pr.ID, err)
+ } else if cnt != 1 {
+ return false, issues_model.ErrIssueAlreadyChanged
+ }
- return true, nil
+ return true, nil
+ })
}
diff --git a/services/repository/avatar.go b/services/repository/avatar.go
index 26bf6da465..998ac42230 100644
--- a/services/repository/avatar.go
+++ b/services/repository/avatar.go
@@ -29,35 +29,30 @@ func UploadAvatar(ctx context.Context, repo *repo_model.Repository, data []byte)
return nil
}
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- oldAvatarPath := repo.CustomAvatarRelativePath()
-
- // Users can upload the same image to other repo - prefix it with ID
- // Then repo will be removed - only it avatar file will be removed
- repo.Avatar = newAvatar
- if err := repo_model.UpdateRepositoryColsNoAutoTime(ctx, repo, "avatar"); err != nil {
- return fmt.Errorf("UploadAvatar: Update repository avatar: %w", err)
- }
-
- if err := storage.SaveFrom(storage.RepoAvatars, repo.CustomAvatarRelativePath(), func(w io.Writer) error {
- _, err := w.Write(avatarData)
- return err
- }); err != nil {
- return fmt.Errorf("UploadAvatar %s failed: Failed to remove old repo avatar %s: %w", repo.RepoPath(), newAvatar, err)
- }
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ oldAvatarPath := repo.CustomAvatarRelativePath()
+
+ // Users can upload the same image to other repo - prefix it with ID
+ // Then repo will be removed - only it avatar file will be removed
+ repo.Avatar = newAvatar
+ if err := repo_model.UpdateRepositoryColsNoAutoTime(ctx, repo, "avatar"); err != nil {
+ return fmt.Errorf("UploadAvatar: Update repository avatar: %w", err)
+ }
- if len(oldAvatarPath) > 0 {
- if err := storage.RepoAvatars.Delete(oldAvatarPath); err != nil {
- return fmt.Errorf("UploadAvatar: Failed to remove old repo avatar %s: %w", oldAvatarPath, err)
+ if err := storage.SaveFrom(storage.RepoAvatars, repo.CustomAvatarRelativePath(), func(w io.Writer) error {
+ _, err := w.Write(avatarData)
+ return err
+ }); err != nil {
+ return fmt.Errorf("UploadAvatar %s failed: Failed to remove old repo avatar %s: %w", repo.RepoPath(), newAvatar, err)
}
- }
- return committer.Commit()
+ if len(oldAvatarPath) > 0 {
+ if err := storage.RepoAvatars.Delete(oldAvatarPath); err != nil {
+ return fmt.Errorf("UploadAvatar: Failed to remove old repo avatar %s: %w", oldAvatarPath, err)
+ }
+ }
+ return nil
+ })
}
// DeleteAvatar deletes the repos's custom avatar.
@@ -70,22 +65,17 @@ func DeleteAvatar(ctx context.Context, repo *repo_model.Repository) error {
avatarPath := repo.CustomAvatarRelativePath()
log.Trace("DeleteAvatar[%d]: %s", repo.ID, avatarPath)
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- repo.Avatar = ""
- if err := repo_model.UpdateRepositoryColsNoAutoTime(ctx, repo, "avatar"); err != nil {
- return fmt.Errorf("DeleteAvatar: Update repository avatar: %w", err)
- }
-
- if err := storage.RepoAvatars.Delete(avatarPath); err != nil {
- return fmt.Errorf("DeleteAvatar: Failed to remove %s: %w", avatarPath, err)
- }
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ repo.Avatar = ""
+ if err := repo_model.UpdateRepositoryColsNoAutoTime(ctx, repo, "avatar"); err != nil {
+ return fmt.Errorf("DeleteAvatar: Update repository avatar: %w", err)
+ }
- return committer.Commit()
+ if err := storage.RepoAvatars.Delete(avatarPath); err != nil {
+ return fmt.Errorf("DeleteAvatar: Failed to remove %s: %w", avatarPath, err)
+ }
+ return nil
+ })
}
// RemoveRandomAvatars removes the randomly generated avatars that were created for repositories
diff --git a/services/repository/collaboration.go b/services/repository/collaboration.go
index b5fc523623..53b3c2e203 100644
--- a/services/repository/collaboration.go
+++ b/services/repository/collaboration.go
@@ -71,40 +71,32 @@ func DeleteCollaboration(ctx context.Context, repo *repo_model.Repository, colla
UserID: collaborator.ID,
}
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- if has, err := db.GetEngine(ctx).Delete(collaboration); err != nil {
- return err
- } else if has == 0 {
- return committer.Commit()
- }
-
- if err := repo.LoadOwner(ctx); err != nil {
- return err
- }
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ if has, err := db.GetEngine(ctx).Delete(collaboration); err != nil {
+ return err
+ } else if has == 0 {
+ return nil
+ }
- if err = access_model.RecalculateAccesses(ctx, repo); err != nil {
- return err
- }
+ if err := repo.LoadOwner(ctx); err != nil {
+ return err
+ }
- if err = repo_model.WatchRepo(ctx, collaborator, repo, false); err != nil {
- return err
- }
+ if err = access_model.RecalculateAccesses(ctx, repo); err != nil {
+ return err
+ }
- if err = ReconsiderWatches(ctx, repo, collaborator); err != nil {
- return err
- }
+ if err = repo_model.WatchRepo(ctx, collaborator, repo, false); err != nil {
+ return err
+ }
- // Unassign a user from any issue (s)he has been assigned to in the repository
- if err := ReconsiderRepoIssuesAssignee(ctx, repo, collaborator); err != nil {
- return err
- }
+ if err = ReconsiderWatches(ctx, repo, collaborator); err != nil {
+ return err
+ }
- return committer.Commit()
+ // Unassign a user from any issue (s)he has been assigned to in the repository
+ return ReconsiderRepoIssuesAssignee(ctx, repo, collaborator)
+ })
}
func ReconsiderRepoIssuesAssignee(ctx context.Context, repo *repo_model.Repository, user *user_model.User) error {
diff --git a/services/repository/repo_team.go b/services/repository/repo_team.go
index 672ee49fea..8ea186f8cc 100644
--- a/services/repository/repo_team.go
+++ b/services/repository/repo_team.go
@@ -86,17 +86,9 @@ func RemoveAllRepositoriesFromTeam(ctx context.Context, t *organization.Team) (e
return nil
}
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- if err = removeAllRepositoriesFromTeam(ctx, t); err != nil {
- return err
- }
-
- return committer.Commit()
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ return removeAllRepositoriesFromTeam(ctx, t)
+ })
}
// removeAllRepositoriesFromTeam removes all repositories from team and recalculates access
@@ -167,17 +159,9 @@ func RemoveRepositoryFromTeam(ctx context.Context, t *organization.Team, repoID
return err
}
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- if err = removeRepositoryFromTeam(ctx, t, repo, true); err != nil {
- return err
- }
-
- return committer.Commit()
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ return removeRepositoryFromTeam(ctx, t, repo, true)
+ })
}
// removeRepositoryFromTeam removes a repository from a team and recalculates access
diff --git a/services/repository/setting.go b/services/repository/setting.go
index e0c787dd2d..b6873691eb 100644
--- a/services/repository/setting.go
+++ b/services/repository/setting.go
@@ -16,41 +16,37 @@ import (
// UpdateRepositoryUnits updates a repository's units
func UpdateRepositoryUnits(ctx context.Context, repo *repo_model.Repository, units []repo_model.RepoUnit, deleteUnitTypes []unit.Type) (err error) {
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- // Delete existing settings of units before adding again
- for _, u := range units {
- deleteUnitTypes = append(deleteUnitTypes, u.Type)
- }
-
- if slices.Contains(deleteUnitTypes, unit.TypeActions) {
- if err := actions_service.CleanRepoScheduleTasks(ctx, repo); err != nil {
- log.Error("CleanRepoScheduleTasks: %v", err)
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ // Delete existing settings of units before adding again
+ for _, u := range units {
+ deleteUnitTypes = append(deleteUnitTypes, u.Type)
}
- }
- for _, u := range units {
- if u.Type == unit.TypeActions {
- if err := actions_service.DetectAndHandleSchedules(ctx, repo); err != nil {
- log.Error("DetectAndHandleSchedules: %v", err)
+ if slices.Contains(deleteUnitTypes, unit.TypeActions) {
+ if err := actions_service.CleanRepoScheduleTasks(ctx, repo); err != nil {
+ log.Error("CleanRepoScheduleTasks: %v", err)
}
- break
}
- }
- if _, err = db.GetEngine(ctx).Where("repo_id = ?", repo.ID).In("type", deleteUnitTypes).Delete(new(repo_model.RepoUnit)); err != nil {
- return err
- }
+ for _, u := range units {
+ if u.Type == unit.TypeActions {
+ if err := actions_service.DetectAndHandleSchedules(ctx, repo); err != nil {
+ log.Error("DetectAndHandleSchedules: %v", err)
+ }
+ break
+ }
+ }
- if len(units) > 0 {
- if err = db.Insert(ctx, units); err != nil {
+ if _, err = db.GetEngine(ctx).Where("repo_id = ?", repo.ID).In("type", deleteUnitTypes).Delete(new(repo_model.RepoUnit)); err != nil {
return err
}
- }
- return committer.Commit()
+ if len(units) > 0 {
+ if err = db.Insert(ctx, units); err != nil {
+ return err
+ }
+ }
+
+ return nil
+ })
}
diff --git a/services/user/avatar.go b/services/user/avatar.go
index 3f87466eaa..df188e5adc 100644
--- a/services/user/avatar.go
+++ b/services/user/avatar.go
@@ -24,26 +24,22 @@ func UploadAvatar(ctx context.Context, u *user_model.User, data []byte) error {
return err
}
- ctx, committer, err := db.TxContext(ctx)
- if err != nil {
- return err
- }
- defer committer.Close()
-
- u.UseCustomAvatar = true
- u.Avatar = avatar.HashAvatar(u.ID, data)
- if err = user_model.UpdateUserCols(ctx, u, "use_custom_avatar", "avatar"); err != nil {
- return fmt.Errorf("updateUser: %w", err)
- }
+ return db.WithTx(ctx, func(ctx context.Context) error {
+ u.UseCustomAvatar = true
+ u.Avatar = avatar.HashAvatar(u.ID, data)
+ if err = user_model.UpdateUserCols(ctx, u, "use_custom_avatar", "avatar"); err != nil {
+ return fmt.Errorf("updateUser: %w", err)
+ }
- if err := storage.SaveFrom(storage.Avatars, u.CustomAvatarRelativePath(), func(w io.Writer) error {
- _, err := w.Write(avatarData)
- return err
- }); err != nil {
- return fmt.Errorf("Failed to create dir %s: %w", u.CustomAvatarRelativePath(), err)
- }
+ if err := storage.SaveFrom(storage.Avatars, u.CustomAvatarRelativePath(), func(w io.Writer) error {
+ _, err := w.Write(avatarData)
+ return err
+ }); err != nil {
+ return fmt.Errorf("Failed to create dir %s: %w", u.CustomAvatarRelativePath(), err)
+ }
- return committer.Commit()
+ return nil
+ })
}
// DeleteAvatar deletes the user's custom avatar.
diff --git a/templates/swagger/ui.tmpl b/templates/swagger/ui.tmpl
index c48ba82fe0..4ff3472807 100644
--- a/templates/swagger/ui.tmpl
+++ b/templates/swagger/ui.tmpl
@@ -5,6 +5,7 @@
<link href="{{AssetUrlPrefix}}/css/swagger.css?v={{AssetVersion}}" rel="stylesheet">
</head>
<body>
+ {{/* TODO: add Help & Glossary to help users understand the API, and explain some concepts like "Owner" */}}
<a class="swagger-back-link" href="{{AppSubUrl}}/">{{svg "octicon-reply"}}{{ctx.Locale.Tr "return_to_gitea"}}</a>
<div id="swagger-ui" data-source="{{AppSubUrl}}/swagger.{{.APIJSONVersion}}.json"></div>
<footer class="page-footer"></footer>
diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl
index 323e0d64ac..35c743dcd4 100644
--- a/templates/swagger/v1_json.tmpl
+++ b/templates/swagger/v1_json.tmpl
@@ -4585,7 +4585,7 @@
"parameters": [
{
"type": "string",
- "description": "name of the owner",
+ "description": "owner of the repo",
"name": "owner",
"in": "path",
"required": true
@@ -4630,7 +4630,7 @@
"parameters": [
{
"type": "string",
- "description": "name of the owner",
+ "description": "owner of the repo",
"name": "owner",
"in": "path",
"required": true
@@ -4674,7 +4674,7 @@
"parameters": [
{
"type": "string",
- "description": "name of the owner",
+ "description": "owner of the repo",
"name": "owner",
"in": "path",
"required": true
@@ -4720,7 +4720,7 @@
"parameters": [
{
"type": "string",
- "description": "name of the owner",
+ "description": "owner of the repo",
"name": "owner",
"in": "path",
"required": true
@@ -4766,7 +4766,7 @@
"parameters": [
{
"type": "string",
- "description": "name of the owner",
+ "description": "owner of the repo",
"name": "owner",
"in": "path",
"required": true
@@ -4823,7 +4823,7 @@
"parameters": [
{
"type": "string",
- "description": "name of the owner",
+ "description": "owner of the repo",
"name": "owner",
"in": "path",
"required": true
@@ -4869,7 +4869,7 @@
"parameters": [
{
"type": "string",
- "description": "name of the owner",
+ "description": "owner of the repo",
"name": "owner",
"in": "path",
"required": true
@@ -5108,7 +5108,7 @@
"parameters": [
{
"type": "string",
- "description": "name of the owner",
+ "description": "owner of the repo",
"name": "owner",
"in": "path",
"required": true
@@ -5189,7 +5189,7 @@
"parameters": [
{
"type": "string",
- "description": "name of the owner",
+ "description": "owner of the repo",
"name": "owner",
"in": "path",
"required": true
@@ -5233,7 +5233,7 @@
"parameters": [
{
"type": "string",
- "description": "name of the owner",
+ "description": "owner of the repo",
"name": "owner",
"in": "path",
"required": true
@@ -5279,7 +5279,7 @@
"parameters": [
{
"type": "string",
- "description": "name of the owner",
+ "description": "owner of the repo",
"name": "owner",
"in": "path",
"required": true
@@ -5331,7 +5331,7 @@
"parameters": [
{
"type": "string",
- "description": "name of the owner",
+ "description": "owner of the repo",
"name": "owner",
"in": "path",
"required": true
@@ -5395,7 +5395,7 @@
"parameters": [
{
"type": "string",
- "description": "owner of the repository",
+ "description": "owner of the repo",
"name": "owner",
"in": "path",
"required": true
@@ -5609,7 +5609,7 @@
"parameters": [
{
"type": "string",
- "description": "name of the owner",
+ "description": "owner of the repo",
"name": "owner",
"in": "path",
"required": true
@@ -5660,7 +5660,7 @@
"parameters": [
{
"type": "string",
- "description": "name of the owner",
+ "description": "owner of the repo",
"name": "owner",
"in": "path",
"required": true
@@ -5704,7 +5704,7 @@
"parameters": [
{
"type": "string",
- "description": "name of the owner",
+ "description": "owner of the repo",
"name": "owner",
"in": "path",
"required": true
@@ -5758,7 +5758,7 @@
"parameters": [
{
"type": "string",
- "description": "name of the owner",
+ "description": "owner of the repo",
"name": "owner",
"in": "path",
"required": true
@@ -5812,7 +5812,7 @@
"parameters": [
{
"type": "string",
- "description": "name of the owner",
+ "description": "owner of the repo",
"name": "owner",
"in": "path",
"required": true
@@ -13424,7 +13424,7 @@
"parameters": [
{
"type": "string",
- "description": "Owner of the repo",
+ "description": "owner of the repo",
"name": "owner",
"in": "path",
"required": true
@@ -17463,7 +17463,7 @@
"parameters": [
{
"type": "string",
- "description": "name of the template repository owner",
+ "description": "owner of the template repository",
"name": "template_owner",
"in": "path",
"required": true
@@ -24968,7 +24968,7 @@
"x-go-package": "code.gitea.io/gitea/modules/structs"
},
"GenerateRepoOption": {
- "description": "GenerateRepoOption options when creating repository using a template",
+ "description": "GenerateRepoOption options when creating a repository using a template",
"type": "object",
"required": [
"owner",
@@ -25006,13 +25006,12 @@
"x-go-name": "Labels"
},
"name": {
- "description": "Name of the repository to create",
"type": "string",
"uniqueItems": true,
"x-go-name": "Name"
},
"owner": {
- "description": "The organization or person who will own the new repository",
+ "description": "the organization's name or individual user's name who will own the new repository",
"type": "string",
"x-go-name": "Owner"
},
@@ -25545,6 +25544,7 @@
"x-go-name": "Index"
},
"owner": {
+ "description": "owner of the issue's repo",
"type": "string",
"x-go-name": "Owner"
},
@@ -25929,7 +25929,7 @@
"x-go-name": "RepoName"
},
"repo_owner": {
- "description": "Name of User or Organisation who will own Repo after migration",
+ "description": "the organization's name or individual user's name who will own the migrated repository",
"type": "string",
"x-go-name": "RepoOwner"
},
@@ -25949,7 +25949,7 @@
"x-go-name": "Service"
},
"uid": {
- "description": "deprecated (only for backwards compatibility)",
+ "description": "deprecated (only for backwards compatibility, use repo_owner instead)",
"type": "integer",
"format": "int64",
"x-go-name": "RepoOwnerID"
diff --git a/tests/integration/editor_test.go b/tests/integration/editor_test.go
index ac47ed0094..ac1fb2abff 100644
--- a/tests/integration/editor_test.go
+++ b/tests/integration/editor_test.go
@@ -415,7 +415,7 @@ func testForkToEditFile(t *testing.T, session *TestSession, user, owner, repo, b
req = NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s-1/_edit/%s/%s?from_base_branch=%s", user, repo, branch, filePath, branch), editRequestForm)
resp = session.MakeRequest(t, req, http.StatusBadRequest)
respJSON := test.ParseJSONError(resp.Body.Bytes())
- assert.Equal(t, `Branch "master" already exists in your fork, please choose a new branch name.`, respJSON.ErrorMessage)
+ assert.Equal(t, `Branch "master" already exists in your fork. Please choose a new branch name.`, respJSON.ErrorMessage)
// change a file in the forked repo (should succeed)
newBranchName := htmlDoc.GetInputValueByName("new_branch_name")