Skip to content

Commit 4ff5342

Browse files
committed
fix: skip MR comment for non-permission errors
Signed-off-by: ab-ghosh <[email protected]>
1 parent 9572f3b commit 4ff5342

File tree

2 files changed

+88
-17
lines changed

2 files changed

+88
-17
lines changed

pkg/provider/gitlab/gitlab.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package gitlab
33
import (
44
"context"
55
"crypto/subtle"
6+
"errors"
67
"fmt"
78
"net/http"
89
"net/url"
@@ -319,12 +320,26 @@ func (v *Provider) CreateStatus(_ context.Context, event *info.Event, statusOpts
319320
v.Logger.Debugf("created commit status on source project ID %d", event.TargetProjectID)
320321
return nil
321322
}
322-
if _, _, err2 := v.Client().Commits.SetCommitStatus(event.TargetProjectID, event.SHA, opt); err2 == nil {
323+
_, _, err2 := v.Client().Commits.SetCommitStatus(event.TargetProjectID, event.SHA, opt)
324+
if err2 == nil {
323325
v.Logger.Debugf("created commit status on target project ID %d", event.TargetProjectID)
324326
// we managed to set the status on the target repo, all good we are done
325327
return nil
326328
}
327-
v.Logger.Debugf("cannot set status with the GitLab token on the target project: %v", err)
329+
v.Logger.Debugf("cannot set status with the GitLab token on the target project: %v", err2)
330+
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)
337+
}
338+
if !isPermErr(err) && !isPermErr(err2) {
339+
v.Logger.Debugf("skipping MR comment as error is not a permission issue")
340+
return nil
341+
}
342+
328343
// we only show the first error as it's likely something the user has more control to fix
329344
// the second err is cryptic as it needs a dummy gitlab pipeline to start
330345
// with and will only give more confusion in the event namespace

pkg/provider/gitlab/gitlab_test.go

Lines changed: 71 additions & 15 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 but continues",
264+
name: "commit status fails on both projects with non-permission error skips MR comment",
265265
wantClient: true,
266266
wantErr: false,
267267
fields: fields{
@@ -273,10 +273,50 @@ func TestCreateStatus(t *testing.T) {
273273
},
274274
event: &info.Event{
275275
TriggerTarget: "pull_request",
276-
SourceProjectID: 404, // Will fail
277-
TargetProjectID: 405, // Will fail
276+
SourceProjectID: 400, // Will fail with 400 (not permission error)
277+
TargetProjectID: 405, // Will fail with 400 (not permission error)
278278
SHA: "abc123",
279279
},
280+
postStr: "", // No MR comment expected for non-permission errors
281+
},
282+
},
283+
{
284+
name: "permission error 403 on source 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: 403, // Will fail with 403 Forbidden
297+
TargetProjectID: 400, // Will fail with 400 (not permission error)
298+
SHA: "abc123def",
299+
},
300+
postStr: "has successfully",
301+
},
302+
},
303+
{
304+
name: "permission error 401 on source creates MR comment",
305+
wantClient: true,
306+
wantErr: false,
307+
fields: fields{
308+
targetProjectID: 100,
309+
},
310+
args: args{
311+
statusOpts: provider.StatusOpts{
312+
Conclusion: "success",
313+
},
314+
event: &info.Event{
315+
TriggerTarget: "pull_request",
316+
SourceProjectID: 401, // Will fail with 401 Unauthorized
317+
TargetProjectID: 400, // Will fail with 400 (not permission error)
318+
SHA: "abc123ghi",
319+
},
280320
postStr: "has successfully",
281321
},
282322
},
@@ -318,31 +358,47 @@ func TestCreateStatus(t *testing.T) {
318358
// Mock source project commit status endpoint
319359
sourceStatusPath := fmt.Sprintf("/projects/%d/statuses/%s", tt.args.event.SourceProjectID, tt.args.event.SHA)
320360
mux.HandleFunc(sourceStatusPath, func(rw http.ResponseWriter, _ *http.Request) {
321-
if tt.args.event.SourceProjectID == 404 {
322-
// Simulate failure on source project
361+
switch tt.args.event.SourceProjectID {
362+
case 400:
363+
rw.WriteHeader(http.StatusBadRequest)
364+
fmt.Fprint(rw, `{"message": "400 Bad Request"}`)
365+
case 401:
366+
rw.WriteHeader(http.StatusUnauthorized)
367+
fmt.Fprint(rw, `{"message": "401 Unauthorized"}`)
368+
case 403:
369+
rw.WriteHeader(http.StatusForbidden)
370+
fmt.Fprint(rw, `{"message": "403 Forbidden"}`)
371+
case 404:
323372
rw.WriteHeader(http.StatusNotFound)
324373
fmt.Fprint(rw, `{"message": "404 Project Not Found"}`)
325-
return
374+
default:
375+
rw.WriteHeader(http.StatusCreated)
376+
fmt.Fprint(rw, `{}`)
326377
}
327-
// Success on source project
328-
rw.WriteHeader(http.StatusCreated)
329-
fmt.Fprint(rw, `{}`)
330378
})
331379
}
332380

333381
if tt.args.event.TargetProjectID != 0 {
334382
// Mock target project commit status endpoint
335383
targetStatusPath := fmt.Sprintf("/projects/%d/statuses/%s", tt.args.event.TargetProjectID, tt.args.event.SHA)
336384
mux.HandleFunc(targetStatusPath, func(rw http.ResponseWriter, _ *http.Request) {
337-
if tt.args.event.TargetProjectID == 404 {
338-
// Simulate failure on target project
385+
switch tt.args.event.TargetProjectID {
386+
case 400, 405:
387+
rw.WriteHeader(http.StatusBadRequest)
388+
fmt.Fprint(rw, `{"message": "400 Bad Request"}`)
389+
case 401:
390+
rw.WriteHeader(http.StatusUnauthorized)
391+
fmt.Fprint(rw, `{"message": "401 Unauthorized"}`)
392+
case 403:
393+
rw.WriteHeader(http.StatusForbidden)
394+
fmt.Fprint(rw, `{"message": "403 Forbidden"}`)
395+
case 404:
339396
rw.WriteHeader(http.StatusNotFound)
340397
fmt.Fprint(rw, `{"message": "404 Project Not Found"}`)
341-
return
398+
default:
399+
rw.WriteHeader(http.StatusCreated)
400+
fmt.Fprint(rw, `{}`)
342401
}
343-
// Success on target project
344-
rw.WriteHeader(http.StatusCreated)
345-
fmt.Fprint(rw, `{}`)
346402
})
347403
}
348404

0 commit comments

Comments
 (0)