Skip to content

Commit bf0d4d9

Browse files
committed
fix(gitlab): skip MR comment for state transition errors
Signed-off-by: ab-ghosh <[email protected]>
1 parent 132ebe4 commit bf0d4d9

File tree

2 files changed

+42
-17
lines changed

2 files changed

+42
-17
lines changed

pkg/provider/gitlab/gitlab.go

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package gitlab
33
import (
44
"context"
55
"crypto/subtle"
6-
"errors"
76
"fmt"
87
"net/http"
98
"net/url"
@@ -328,15 +327,15 @@ func (v *Provider) CreateStatus(_ context.Context, event *info.Event, statusOpts
328327
}
329328
v.Logger.Debugf("cannot set status with the GitLab token on the target project: %v", err2)
330329

331-
// Only fall back to creating MR comments if either error is a permission issue (401/403).
332-
// For other errors (e.g., state transition errors like "Cannot transition status via :run from :running"),
333-
// the status might already be set, so we should not create a comment.
334-
isPermErr := func(e error) bool {
335-
var errResp *gitlab.ErrorResponse
336-
return errors.As(e, &errResp) && (errResp.Response.StatusCode == http.StatusUnauthorized || errResp.Response.StatusCode == http.StatusForbidden)
330+
// Skip creating MR comments if the error is a state transition error
331+
// (e.g., "Cannot transition status via :run from :running").
332+
// This means the status is already set, so we should not create a comment.
333+
// For other errors (permission issues, network errors, etc.), we fall back to comments.
334+
isTransitionErr := func(e error) bool {
335+
return e != nil && strings.Contains(e.Error(), "Cannot transition status")
337336
}
338-
if !isPermErr(err) && !isPermErr(err2) {
339-
v.Logger.Debugf("skipping MR comment as error is not a permission issue")
337+
if isTransitionErr(err) || isTransitionErr(err2) {
338+
v.Logger.Debugf("skipping MR comment as error is a state transition issue (status already set)")
340339
return nil
341340
}
342341

pkg/provider/gitlab/gitlab_test.go

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ func TestCreateStatus(t *testing.T) {
261261
},
262262
},
263263
{
264-
name: "commit status fails on both projects with non-permission error skips MR comment",
264+
name: "commit status fails with state transition error skips MR comment",
265265
wantClient: true,
266266
wantErr: false,
267267
fields: fields{
@@ -273,11 +273,31 @@ func TestCreateStatus(t *testing.T) {
273273
},
274274
event: &info.Event{
275275
TriggerTarget: "pull_request",
276-
SourceProjectID: 400, // Will fail with 400 (not permission error)
277-
TargetProjectID: 405, // Will fail with 400 (not permission error)
276+
SourceProjectID: 422, // Will fail with "Cannot transition status" error
277+
TargetProjectID: 423, // Will fail with "Cannot transition status" error
278278
SHA: "abc123",
279279
},
280-
postStr: "", // No MR comment expected for non-permission errors
280+
postStr: "", // No MR comment expected for state transition errors
281+
},
282+
},
283+
{
284+
name: "generic error on both projects creates MR comment",
285+
wantClient: true,
286+
wantErr: false,
287+
fields: fields{
288+
targetProjectID: 100,
289+
},
290+
args: args{
291+
statusOpts: provider.StatusOpts{
292+
Conclusion: "success",
293+
},
294+
event: &info.Event{
295+
TriggerTarget: "pull_request",
296+
SourceProjectID: 400, // Will fail with generic 400 error
297+
TargetProjectID: 405, // Will fail with generic 400 error
298+
SHA: "abc123def",
299+
},
300+
postStr: "has successfully", // MR comment expected for non-transition errors
281301
},
282302
},
283303
{
@@ -294,8 +314,8 @@ func TestCreateStatus(t *testing.T) {
294314
event: &info.Event{
295315
TriggerTarget: "pull_request",
296316
SourceProjectID: 403, // Will fail with 403 Forbidden
297-
TargetProjectID: 400, // Will fail with 400 (not permission error)
298-
SHA: "abc123def",
317+
TargetProjectID: 400, // Will fail with generic 400 error
318+
SHA: "abc123ghi",
299319
},
300320
postStr: "has successfully",
301321
},
@@ -314,8 +334,8 @@ func TestCreateStatus(t *testing.T) {
314334
event: &info.Event{
315335
TriggerTarget: "pull_request",
316336
SourceProjectID: 401, // Will fail with 401 Unauthorized
317-
TargetProjectID: 400, // Will fail with 400 (not permission error)
318-
SHA: "abc123ghi",
337+
TargetProjectID: 400, // Will fail with generic 400 error
338+
SHA: "abc123jkl",
319339
},
320340
postStr: "has successfully",
321341
},
@@ -371,6 +391,9 @@ func TestCreateStatus(t *testing.T) {
371391
case 404:
372392
rw.WriteHeader(http.StatusNotFound)
373393
fmt.Fprint(rw, `{"message": "404 Project Not Found"}`)
394+
case 422:
395+
rw.WriteHeader(http.StatusBadRequest)
396+
fmt.Fprint(rw, `{"message": "Cannot transition status via :run from :running"}`)
374397
default:
375398
rw.WriteHeader(http.StatusCreated)
376399
fmt.Fprint(rw, `{}`)
@@ -395,6 +418,9 @@ func TestCreateStatus(t *testing.T) {
395418
case 404:
396419
rw.WriteHeader(http.StatusNotFound)
397420
fmt.Fprint(rw, `{"message": "404 Project Not Found"}`)
421+
case 423:
422+
rw.WriteHeader(http.StatusBadRequest)
423+
fmt.Fprint(rw, `{"message": "Cannot transition status via :run from :running"}`)
398424
default:
399425
rw.WriteHeader(http.StatusCreated)
400426
fmt.Fprint(rw, `{}`)

0 commit comments

Comments
 (0)