Skip to content

Commit 2d9d7ea

Browse files
refactor(cmd): route upload + sbom through httpclient, keep test injection (OD-30)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 71521ba commit 2d9d7ea

3 files changed

Lines changed: 56 additions & 6 deletions

File tree

cmd/upload.go

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"codacy/cli-v2/config"
66
"codacy/cli-v2/domain"
77
"codacy/cli-v2/plugins"
8+
"codacy/cli-v2/utils/httpclient"
89
"encoding/json"
910
"fmt"
1011
"io"
@@ -251,7 +252,11 @@ func resultsFinalWithProjectToken(commitUUID string, projectToken string) {
251252
req.Header.Set("Content-Type", "application/json")
252253
req.Header.Set("project-token", projectToken)
253254

254-
client := &http.Client{}
255+
client, err := httpclient.New()
256+
if err != nil {
257+
fmt.Println("Error:", err)
258+
return
259+
}
255260
resp, err := client.Do(req)
256261
if err != nil {
257262
fmt.Println("Error:", err)
@@ -269,7 +274,11 @@ func resultsFinalWithAPIToken(commitUUID string, apiToken string, provider strin
269274
req.Header.Set("Content-Type", "application/json")
270275
req.Header.Set("api-token", apiToken)
271276

272-
client := &http.Client{}
277+
client, err := httpclient.New()
278+
if err != nil {
279+
fmt.Println("Error:", err)
280+
return
281+
}
273282
resp, err := client.Do(req)
274283
if err != nil {
275284
fmt.Println("Error:", err)
@@ -341,7 +350,12 @@ func sendResultsWithProjectToken(payload []map[string]interface{}, commitUUID st
341350
req.Header.Set("content-type", "application/json")
342351
req.Header.Set("project-token", projectToken)
343352

344-
resp, err := http.DefaultClient.Do(req)
353+
client, err := httpclient.New()
354+
if err != nil {
355+
fmt.Printf("Error creating http client: %v\n", err)
356+
os.Exit(1)
357+
}
358+
resp, err := client.Do(req)
345359
if err != nil {
346360
fmt.Printf("Error sending results: %v\n", err)
347361
os.Exit(1)
@@ -372,7 +386,12 @@ func sendResultsWithAPIToken(payload []map[string]interface{}, commitUUID string
372386
req.Header.Set("content-type", "application/json")
373387
req.Header.Set("api-token", apiToken)
374388

375-
resp, err := http.DefaultClient.Do(req)
389+
client, err := httpclient.New()
390+
if err != nil {
391+
fmt.Printf("Error creating http client: %v\n", err)
392+
os.Exit(1)
393+
}
394+
resp, err := client.Do(req)
376395
if err != nil {
377396
fmt.Printf("Error sending results: %v\n", err)
378397
os.Exit(1)

cmd/upload_sbom.go

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"strings"
1212
"time"
1313

14+
"codacy/cli-v2/utils/httpclient"
1415
"codacy/cli-v2/utils/logger"
1516

1617
"github.com/fatih/color"
@@ -29,14 +30,25 @@ var (
2930
sbomFormat string
3031
sbomBaseURL string
3132

32-
sbomHTTPClient httpDoer = &http.Client{Timeout: 5 * time.Minute}
33+
// sbomHTTPClient is nil by default and resolved lazily via defaultSBOMClient.
34+
// Tests may set it to a stub implementing httpDoer.
35+
sbomHTTPClient httpDoer
3336
)
3437

3538
// httpDoer abstracts the Do method of http.Client for testing.
3639
type httpDoer interface {
3740
Do(req *http.Request) (*http.Response, error)
3841
}
3942

43+
// defaultSBOMClient returns the injected client if set, else a factory client
44+
// honoring proxy/TLS configuration.
45+
func defaultSBOMClient() (httpDoer, error) {
46+
if sbomHTTPClient != nil {
47+
return sbomHTTPClient, nil
48+
}
49+
return httpclient.New(httpclient.WithTimeout(5 * time.Minute))
50+
}
51+
4052
func init() {
4153
uploadSBOMCmd.Flags().StringVarP(&sbomAPIToken, "api-token", "a", "", "API token for Codacy API (required)")
4254
uploadSBOMCmd.Flags().StringVarP(&sbomProvider, "provider", "p", "", "Git provider (gh, gl, bb) (required)")
@@ -239,7 +251,11 @@ func uploadSBOMToCodacy(sbomPath, imageName, tag string, params sbomUploadParams
239251
req.Header.Set("Accept", "application/json")
240252
req.Header.Set("api-token", params.apiToken)
241253

242-
resp, err := sbomHTTPClient.Do(req)
254+
client, err := defaultSBOMClient()
255+
if err != nil {
256+
return fmt.Errorf("failed to create http client: %w", err)
257+
}
258+
resp, err := client.Do(req)
243259
if err != nil {
244260
return fmt.Errorf("request failed: %w", err)
245261
}

cmd/upload_sbom_test.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,25 @@ import (
77
"net/http/httptest"
88
"os"
99
"testing"
10+
"time"
1011

1112
"github.com/stretchr/testify/assert"
13+
"github.com/stretchr/testify/require"
1214
)
1315

16+
func TestDefaultSBOMClient_UsesHTTPClientFactory(t *testing.T) {
17+
saved := sbomHTTPClient
18+
defer func() { sbomHTTPClient = saved }()
19+
20+
sbomHTTPClient = nil // force default path
21+
c, err := defaultSBOMClient()
22+
require.NoError(t, err)
23+
require.NotNil(t, c)
24+
hc, ok := c.(*http.Client)
25+
require.True(t, ok)
26+
assert.Equal(t, 5*time.Minute, hc.Timeout)
27+
}
28+
1429
type sbomTestState struct {
1530
apiToken string
1631
provider string

0 commit comments

Comments
 (0)