This is an automated email from the ASF dual-hosted git repository.

klesh pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/devlake.git


The following commit(s) were added to refs/heads/main by this push:
     new e744aefe0 fix(github): ignore 404 when collecting unfinished pull 
requests (#9140) (#9145)
e744aefe0 is described below

commit e744aefe04473062d1da46934da256aad8112add
Author: Keerthan Poojary <[email protected]>
AuthorDate: Fri Sep 18 12:10:05 2026 +0530

    fix(github): ignore 404 when collecting unfinished pull requests (#9140) 
(#9145)
---
 backend/plugins/github/tasks/pr_collector.go |   1 +
 backend/plugins/github/tasks/shared_test.go  | 126 +++++++++++++++++++++++++++
 2 files changed, 127 insertions(+)

diff --git a/backend/plugins/github/tasks/pr_collector.go 
b/backend/plugins/github/tasks/pr_collector.go
index 05ca03bee..9c90470ec 100644
--- a/backend/plugins/github/tasks/pr_collector.go
+++ b/backend/plugins/github/tasks/pr_collector.go
@@ -129,6 +129,7 @@ func CollectApiPullRequests(taskCtx plugin.SubTaskContext) 
errors.Error {
                                        res.Body.Close()
                                        return []json.RawMessage{body}, nil
                                },
+                               AfterResponse: ignoreHTTPStatus404,
                        },
                },
        })
diff --git a/backend/plugins/github/tasks/shared_test.go 
b/backend/plugins/github/tasks/shared_test.go
new file mode 100644
index 000000000..8bcb4249e
--- /dev/null
+++ b/backend/plugins/github/tasks/shared_test.go
@@ -0,0 +1,126 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package tasks
+
+import (
+       "bytes"
+       "io"
+       "net/http"
+       "testing"
+
+       "github.com/apache/devlake/core/errors"
+       "github.com/apache/devlake/helpers/pluginhelper/api"
+       "github.com/stretchr/testify/assert"
+       "github.com/stretchr/testify/require"
+)
+
+func makeTestResponse(statusCode int) *http.Response {
+       return &http.Response{
+               StatusCode: statusCode,
+               Body:       io.NopCloser(bytes.NewBufferString("")),
+               Request:    &http.Request{},
+       }
+}
+
+func TestIgnoreHTTPStatus404(t *testing.T) {
+       tests := []struct {
+               name       string
+               statusCode int
+               wantIgnore bool
+               wantUnauth bool
+               wantNil    bool
+       }{
+               {
+                       name:       "404 returns ErrIgnoreAndContinue",
+                       statusCode: http.StatusNotFound,
+                       wantIgnore: true,
+               },
+               {
+                       name:       "401 returns unauthorized error",
+                       statusCode: http.StatusUnauthorized,
+                       wantUnauth: true,
+               },
+               {
+                       name:       "200 returns nil",
+                       statusCode: http.StatusOK,
+                       wantNil:    true,
+               },
+               {
+                       name:       "403 returns nil",
+                       statusCode: http.StatusForbidden,
+                       wantNil:    true,
+               },
+               {
+                       name:       "500 returns nil",
+                       statusCode: http.StatusInternalServerError,
+                       wantNil:    true,
+               },
+       }
+
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       res := makeTestResponse(tt.statusCode)
+                       err := ignoreHTTPStatus404(res)
+                       if tt.wantIgnore {
+                               assert.Equal(t, api.ErrIgnoreAndContinue, err)
+                       } else if tt.wantUnauth {
+                               require.NotNil(t, err)
+                               assert.Equal(t, errors.Unauthorized, 
err.GetType())
+                       } else if tt.wantNil {
+                               assert.Nil(t, err)
+                       }
+               })
+       }
+}
+
+func TestIgnoreHTTPStatus422(t *testing.T) {
+       tests := []struct {
+               name       string
+               statusCode int
+               wantIgnore bool
+               wantNil    bool
+       }{
+               {
+                       name:       "422 returns ErrIgnoreAndContinue",
+                       statusCode: http.StatusUnprocessableEntity,
+                       wantIgnore: true,
+               },
+               {
+                       name:       "200 returns nil",
+                       statusCode: http.StatusOK,
+                       wantNil:    true,
+               },
+               {
+                       name:       "404 returns nil",
+                       statusCode: http.StatusNotFound,
+                       wantNil:    true,
+               },
+       }
+
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       res := makeTestResponse(tt.statusCode)
+                       err := ignoreHTTPStatus422(res)
+                       if tt.wantIgnore {
+                               assert.Equal(t, api.ErrIgnoreAndContinue, err)
+                       } else if tt.wantNil {
+                               assert.Nil(t, err)
+                       }
+               })
+       }
+}

Reply via email to