@@ -28,38 +28,40 @@ import (
28
28
29
29
// UpdateIssueCols updates cols of issue
30
30
func UpdateIssueCols (ctx context.Context , issue * Issue , cols ... string ) error {
31
- if _ , err := db .GetEngine (ctx ).ID (issue .ID ).Cols (cols ... ).Update (issue ); err != nil {
32
- return err
33
- }
34
- return nil
31
+ _ , err := db .GetEngine (ctx ).ID (issue .ID ).Cols (cols ... ).Update (issue )
32
+ return err
35
33
}
36
34
37
- func ChangeIssueStatus (ctx context.Context , issue * Issue , doer * user_model.User , isClosed , isMergePull bool ) (* Comment , error ) {
38
- // Reload the issue
39
- currentIssue , err := GetIssueByID (ctx , issue .ID )
40
- if err != nil {
41
- return nil , err
42
- }
35
+ // ErrIssueIsClosed is used when close a closed issue
36
+ type ErrIssueIsClosed struct {
37
+ ID int64
38
+ RepoID int64
39
+ Index int64
40
+ IsPull bool
41
+ }
43
42
44
- // Nothing should be performed if current status is same as target status
45
- if currentIssue .IsClosed == isClosed {
46
- if ! issue .IsPull {
47
- return nil , ErrIssueWasClosed {
48
- ID : issue .ID ,
49
- }
50
- }
51
- return nil , ErrPullWasClosed {
52
- ID : issue .ID ,
53
- }
54
- }
43
+ // IsErrIssueIsClosed checks if an error is a ErrIssueIsClosed.
44
+ func IsErrIssueIsClosed (err error ) bool {
45
+ _ , ok := err .(ErrIssueIsClosed )
46
+ return ok
47
+ }
55
48
56
- issue . IsClosed = isClosed
57
- return doChangeIssueStatus ( ctx , issue , doer , isMergePull )
49
+ func ( err ErrIssueIsClosed ) Error () string {
50
+ 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 )
58
51
}
59
52
60
- func doChangeIssueStatus (ctx context.Context , issue * Issue , doer * user_model.User , isMergePull bool ) (* Comment , error ) {
53
+ func SetIssueAsClosed (ctx context.Context , issue * Issue , doer * user_model.User , isMergePull bool ) (* Comment , error ) {
54
+ if issue .IsClosed {
55
+ return nil , ErrIssueIsClosed {
56
+ ID : issue .ID ,
57
+ RepoID : issue .RepoID ,
58
+ Index : issue .Index ,
59
+ IsPull : issue .IsPull ,
60
+ }
61
+ }
62
+
61
63
// Check for open dependencies
62
- if issue .IsClosed && issue . Repo .IsDependenciesEnabled (ctx ) {
64
+ if issue .Repo .IsDependenciesEnabled (ctx ) {
63
65
// 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
64
66
noDeps , err := IssueNoDependenciesLeft (ctx , issue )
65
67
if err != nil {
@@ -71,16 +73,63 @@ func doChangeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.Use
71
73
}
72
74
}
73
75
74
- if issue .IsClosed {
75
- issue .ClosedUnix = timeutil .TimeStampNow ()
76
- } else {
77
- issue .ClosedUnix = 0
76
+ issue .IsClosed = true
77
+ issue .ClosedUnix = timeutil .TimeStampNow ()
78
+
79
+ if cnt , err := db .GetEngine (ctx ).ID (issue .ID ).Cols ("is_closed" , "closed_unix" ).
80
+ Where ("is_closed = ?" , false ).
81
+ Update (issue ); err != nil {
82
+ return nil , err
83
+ } else if cnt != 1 {
84
+ return nil , ErrIssueAlreadyChanged
78
85
}
79
86
80
- if err := UpdateIssueCols (ctx , issue , "is_closed" , "closed_unix" ); err != nil {
87
+ return updateIssueNumbers (ctx , issue , doer , util .Iif (isMergePull , CommentTypeMergePull , CommentTypeClose ))
88
+ }
89
+
90
+ // ErrIssueIsOpen is used when reopen an opened issue
91
+ type ErrIssueIsOpen struct {
92
+ ID int64
93
+ RepoID int64
94
+ IsPull bool
95
+ Index int64
96
+ }
97
+
98
+ // IsErrIssueIsOpen checks if an error is a ErrIssueIsOpen.
99
+ func IsErrIssueIsOpen (err error ) bool {
100
+ _ , ok := err .(ErrIssueIsOpen )
101
+ return ok
102
+ }
103
+
104
+ func (err ErrIssueIsOpen ) Error () string {
105
+ 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 )
106
+ }
107
+
108
+ func setIssueAsReopen (ctx context.Context , issue * Issue , doer * user_model.User ) (* Comment , error ) {
109
+ if ! issue .IsClosed {
110
+ return nil , ErrIssueIsOpen {
111
+ ID : issue .ID ,
112
+ RepoID : issue .RepoID ,
113
+ Index : issue .Index ,
114
+ IsPull : issue .IsPull ,
115
+ }
116
+ }
117
+
118
+ issue .IsClosed = false
119
+ issue .ClosedUnix = 0
120
+
121
+ if cnt , err := db .GetEngine (ctx ).ID (issue .ID ).Cols ("is_closed" , "closed_unix" ).
122
+ Where ("is_closed = ?" , true ).
123
+ Update (issue ); err != nil {
81
124
return nil , err
125
+ } else if cnt != 1 {
126
+ return nil , ErrIssueAlreadyChanged
82
127
}
83
128
129
+ return updateIssueNumbers (ctx , issue , doer , CommentTypeReopen )
130
+ }
131
+
132
+ func updateIssueNumbers (ctx context.Context , issue * Issue , doer * user_model.User , cmtType CommentType ) (* Comment , error ) {
84
133
// Update issue count of labels
85
134
if err := issue .LoadLabels (ctx ); err != nil {
86
135
return nil , err
@@ -103,14 +152,6 @@ func doChangeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.Use
103
152
return nil , err
104
153
}
105
154
106
- // New action comment
107
- cmtType := CommentTypeClose
108
- if ! issue .IsClosed {
109
- cmtType = CommentTypeReopen
110
- } else if isMergePull {
111
- cmtType = CommentTypeMergePull
112
- }
113
-
114
155
return CreateComment (ctx , & CreateCommentOptions {
115
156
Type : cmtType ,
116
157
Doer : doer ,
@@ -134,7 +175,7 @@ func CloseIssue(ctx context.Context, issue *Issue, doer *user_model.User) (*Comm
134
175
}
135
176
defer committer .Close ()
136
177
137
- comment , err := ChangeIssueStatus (ctx , issue , doer , true , false )
178
+ comment , err := SetIssueAsClosed (ctx , issue , doer , false )
138
179
if err != nil {
139
180
return nil , err
140
181
}
@@ -159,7 +200,7 @@ func ReopenIssue(ctx context.Context, issue *Issue, doer *user_model.User) (*Com
159
200
}
160
201
defer committer .Close ()
161
202
162
- comment , err := ChangeIssueStatus (ctx , issue , doer , false , false )
203
+ comment , err := setIssueAsReopen (ctx , issue , doer )
163
204
if err != nil {
164
205
return nil , err
165
206
}
0 commit comments