Add missed transaction on setmerged (#33079)
Follow #33045. There are two updates on `Set Merged`, which should be in one transaction. This also introduced some refactors for changeissuestatus to make it more clear.
This commit is contained in:
parent
a8e7caedfa
commit
67aeb1f896
7 changed files with 123 additions and 148 deletions
|
@ -46,23 +46,6 @@ func (err ErrIssueNotExist) Unwrap() error {
|
|||
return util.ErrNotExist
|
||||
}
|
||||
|
||||
// ErrIssueIsClosed represents a "IssueIsClosed" kind of error.
|
||||
type ErrIssueIsClosed struct {
|
||||
ID int64
|
||||
RepoID int64
|
||||
Index int64
|
||||
}
|
||||
|
||||
// IsErrIssueIsClosed checks if an error is a ErrIssueNotExist.
|
||||
func IsErrIssueIsClosed(err error) bool {
|
||||
_, ok := err.(ErrIssueIsClosed)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrIssueIsClosed) Error() string {
|
||||
return fmt.Sprintf("issue is closed [id: %d, repo_id: %d, index: %d]", err.ID, err.RepoID, err.Index)
|
||||
}
|
||||
|
||||
// ErrNewIssueInsert is used when the INSERT statement in newIssue fails
|
||||
type ErrNewIssueInsert struct {
|
||||
OriginalError error
|
||||
|
@ -78,22 +61,6 @@ func (err ErrNewIssueInsert) Error() string {
|
|||
return err.OriginalError.Error()
|
||||
}
|
||||
|
||||
// ErrIssueWasClosed is used when close a closed issue
|
||||
type ErrIssueWasClosed struct {
|
||||
ID int64
|
||||
Index int64
|
||||
}
|
||||
|
||||
// IsErrIssueWasClosed checks if an error is a ErrIssueWasClosed.
|
||||
func IsErrIssueWasClosed(err error) bool {
|
||||
_, ok := err.(ErrIssueWasClosed)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrIssueWasClosed) Error() string {
|
||||
return fmt.Sprintf("Issue [%d] %d was already closed", err.ID, err.Index)
|
||||
}
|
||||
|
||||
var ErrIssueAlreadyChanged = util.NewInvalidArgumentErrorf("the issue is already changed")
|
||||
|
||||
// Issue represents an issue or pull request of repository.
|
||||
|
|
|
@ -28,38 +28,40 @@ import (
|
|||
|
||||
// UpdateIssueCols updates cols of issue
|
||||
func UpdateIssueCols(ctx context.Context, issue *Issue, cols ...string) error {
|
||||
if _, err := db.GetEngine(ctx).ID(issue.ID).Cols(cols...).Update(issue); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
_, err := db.GetEngine(ctx).ID(issue.ID).Cols(cols...).Update(issue)
|
||||
return err
|
||||
}
|
||||
|
||||
func ChangeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.User, isClosed, isMergePull bool) (*Comment, error) {
|
||||
// Reload the issue
|
||||
currentIssue, err := GetIssueByID(ctx, issue.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// ErrIssueIsClosed is used when close a closed issue
|
||||
type ErrIssueIsClosed struct {
|
||||
ID int64
|
||||
RepoID int64
|
||||
Index int64
|
||||
IsPull bool
|
||||
}
|
||||
|
||||
// Nothing should be performed if current status is same as target status
|
||||
if currentIssue.IsClosed == isClosed {
|
||||
if !issue.IsPull {
|
||||
return nil, ErrIssueWasClosed{
|
||||
ID: issue.ID,
|
||||
}
|
||||
}
|
||||
return nil, ErrPullWasClosed{
|
||||
ID: issue.ID,
|
||||
// IsErrIssueIsClosed checks if an error is a ErrIssueIsClosed.
|
||||
func IsErrIssueIsClosed(err error) bool {
|
||||
_, ok := err.(ErrIssueIsClosed)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrIssueIsClosed) Error() string {
|
||||
return fmt.Sprintf("%s [id: %d, repo_id: %d, index: %d] is already closed", util.Iif(err.IsPull, "Pull Request", "Issue"), err.ID, err.RepoID, err.Index)
|
||||
}
|
||||
|
||||
func SetIssueAsClosed(ctx context.Context, issue *Issue, doer *user_model.User, isMergePull bool) (*Comment, error) {
|
||||
if issue.IsClosed {
|
||||
return nil, ErrIssueIsClosed{
|
||||
ID: issue.ID,
|
||||
RepoID: issue.RepoID,
|
||||
Index: issue.Index,
|
||||
IsPull: issue.IsPull,
|
||||
}
|
||||
}
|
||||
|
||||
issue.IsClosed = isClosed
|
||||
return doChangeIssueStatus(ctx, issue, doer, isMergePull)
|
||||
}
|
||||
|
||||
func doChangeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.User, isMergePull bool) (*Comment, error) {
|
||||
// Check for open dependencies
|
||||
if issue.IsClosed && issue.Repo.IsDependenciesEnabled(ctx) {
|
||||
if issue.Repo.IsDependenciesEnabled(ctx) {
|
||||
// only check if dependencies are enabled and we're about to close an issue, otherwise reopening an issue would fail when there are unsatisfied dependencies
|
||||
noDeps, err := IssueNoDependenciesLeft(ctx, issue)
|
||||
if err != nil {
|
||||
|
@ -71,16 +73,63 @@ func doChangeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.Use
|
|||
}
|
||||
}
|
||||
|
||||
if issue.IsClosed {
|
||||
issue.ClosedUnix = timeutil.TimeStampNow()
|
||||
} else {
|
||||
issue.ClosedUnix = 0
|
||||
}
|
||||
issue.IsClosed = true
|
||||
issue.ClosedUnix = timeutil.TimeStampNow()
|
||||
|
||||
if err := UpdateIssueCols(ctx, issue, "is_closed", "closed_unix"); err != nil {
|
||||
if cnt, err := db.GetEngine(ctx).ID(issue.ID).Cols("is_closed", "closed_unix").
|
||||
Where("is_closed = ?", false).
|
||||
Update(issue); err != nil {
|
||||
return nil, err
|
||||
} else if cnt != 1 {
|
||||
return nil, ErrIssueAlreadyChanged
|
||||
}
|
||||
|
||||
return updateIssueNumbers(ctx, issue, doer, util.Iif(isMergePull, CommentTypeMergePull, CommentTypeClose))
|
||||
}
|
||||
|
||||
// ErrIssueIsOpen is used when reopen an opened issue
|
||||
type ErrIssueIsOpen struct {
|
||||
ID int64
|
||||
RepoID int64
|
||||
IsPull bool
|
||||
Index int64
|
||||
}
|
||||
|
||||
// IsErrIssueIsOpen checks if an error is a ErrIssueIsOpen.
|
||||
func IsErrIssueIsOpen(err error) bool {
|
||||
_, ok := err.(ErrIssueIsOpen)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrIssueIsOpen) Error() string {
|
||||
return fmt.Sprintf("%s [id: %d, repo_id: %d, index: %d] is already open", util.Iif(err.IsPull, "Pull Request", "Issue"), err.ID, err.RepoID, err.Index)
|
||||
}
|
||||
|
||||
func setIssueAsReopen(ctx context.Context, issue *Issue, doer *user_model.User) (*Comment, error) {
|
||||
if !issue.IsClosed {
|
||||
return nil, ErrIssueIsOpen{
|
||||
ID: issue.ID,
|
||||
RepoID: issue.RepoID,
|
||||
Index: issue.Index,
|
||||
IsPull: issue.IsPull,
|
||||
}
|
||||
}
|
||||
|
||||
issue.IsClosed = false
|
||||
issue.ClosedUnix = 0
|
||||
|
||||
if cnt, err := db.GetEngine(ctx).ID(issue.ID).Cols("is_closed", "closed_unix").
|
||||
Where("is_closed = ?", true).
|
||||
Update(issue); err != nil {
|
||||
return nil, err
|
||||
} else if cnt != 1 {
|
||||
return nil, ErrIssueAlreadyChanged
|
||||
}
|
||||
|
||||
return updateIssueNumbers(ctx, issue, doer, CommentTypeReopen)
|
||||
}
|
||||
|
||||
func updateIssueNumbers(ctx context.Context, issue *Issue, doer *user_model.User, cmtType CommentType) (*Comment, error) {
|
||||
// Update issue count of labels
|
||||
if err := issue.LoadLabels(ctx); err != nil {
|
||||
return nil, err
|
||||
|
@ -103,14 +152,6 @@ func doChangeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.Use
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// New action comment
|
||||
cmtType := CommentTypeClose
|
||||
if !issue.IsClosed {
|
||||
cmtType = CommentTypeReopen
|
||||
} else if isMergePull {
|
||||
cmtType = CommentTypeMergePull
|
||||
}
|
||||
|
||||
return CreateComment(ctx, &CreateCommentOptions{
|
||||
Type: cmtType,
|
||||
Doer: doer,
|
||||
|
@ -134,7 +175,7 @@ func CloseIssue(ctx context.Context, issue *Issue, doer *user_model.User) (*Comm
|
|||
}
|
||||
defer committer.Close()
|
||||
|
||||
comment, err := ChangeIssueStatus(ctx, issue, doer, true, false)
|
||||
comment, err := SetIssueAsClosed(ctx, issue, doer, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -159,7 +200,7 @@ func ReopenIssue(ctx context.Context, issue *Issue, doer *user_model.User) (*Com
|
|||
}
|
||||
defer committer.Close()
|
||||
|
||||
comment, err := ChangeIssueStatus(ctx, issue, doer, false, false)
|
||||
comment, err := setIssueAsReopen(ctx, issue, doer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -80,22 +80,6 @@ func (err ErrPullRequestAlreadyExists) Unwrap() error {
|
|||
return util.ErrAlreadyExist
|
||||
}
|
||||
|
||||
// ErrPullWasClosed is used close a closed pull request
|
||||
type ErrPullWasClosed struct {
|
||||
ID int64
|
||||
Index int64
|
||||
}
|
||||
|
||||
// IsErrPullWasClosed checks if an error is a ErrErrPullWasClosed.
|
||||
func IsErrPullWasClosed(err error) bool {
|
||||
_, ok := err.(ErrPullWasClosed)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrPullWasClosed) Error() string {
|
||||
return fmt.Sprintf("Pull request [%d] %d was already closed", err.ID, err.Index)
|
||||
}
|
||||
|
||||
// PullRequestType defines pull request type
|
||||
type PullRequestType int
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue