Skip to content

Commit d445d0e

Browse files
chore: enable errcheck, nolintlint, and nilnil linters (#3122)
* Enable three new golangci-lint checks to improve error handling and code quality. Ensures all error returns are explicitly handled or intentionally ignored to prevent silent failures. **Fixed:** - `internal/sanitizer/sanitizer.go` - Wrapped async audit logging in closure to explicitly discard error. Audit logging is fire-and-forget to avoid blocking sanitization. Functions returning `(nil, nil)` are ambiguous - callers cannot distinguish between success-with-no-data and error states. **Fixed:** - `pkg/common/cluster/clusterutil.go` - Removed special handling of `ErrReserveFull`. Library code now reports all errors naturally using `%w` for proper error wrapping. - `cmd/osde2e/provision/cmd.go` - Handles `ErrReserveFull` at application boundary where business logic belongs. Treats "reserve full" as success, all other errors propagate. - `pkg/e2e/e2e.go` + `pkg/common/aws/s3.go` - Moved S3 bucket check to caller. Application layer decides whether to upload; library layer just uploads. Added TODO for future refactor to use dependency injection. - `test/sdn_migration/sdn_migration_test.go` - Changed terraform destroy to return empty map instead of `(nil, nil)` to indicate success-with-no-output. Ensures linter suppressions are properly formatted and prevents malformed directives. **Fixed:** - `pkg/common/providers/ocmprovider/cluster.go` - Fixed `//nolint:gocyclo` formatting (removed space). - `pkg/common/concurrentviper/generated.go` - Removed malformed `// nolint` directive. File is already excluded via config since generator is broken. - `cmd/osde2e/provision/cmd.go` - Removed unnecessary `//nolint:gocyclo` directive. Function complexity was reduced. - **Clearer error contracts** - No more ambiguous (nil, nil) returns - **Better separation of concerns** - Libraries report errors, applications interpret them - **Explicit error handling** - All errors are handled or intentionally discarded - **Type-safe error wrapping** - Using `%w` instead of `%v` for proper error chains All changes maintain existing behavior while making error handling more explicit and maintainable. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * fix: add ReserveFull error logging back --------- Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent 6647d48 commit d445d0e

10 files changed

Lines changed: 35 additions & 39 deletions

File tree

.golangci.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,19 @@ linters:
66
default: none
77
enable:
88
- copyloopvar
9+
- errcheck
910
- gocyclo
1011
- govet
1112
- ineffassign
1213
- loggercheck
1314
- mirror
1415
- misspell
16+
- nilnil
17+
- nolintlint
1518
- staticcheck
1619
- unconvert
17-
- unused
1820
- unparam
21+
- unused
1922
exclusions:
2023
generated: lax
2124
presets:
@@ -32,6 +35,7 @@ linters:
3235
- third_party$
3336
- builtin$
3437
- examples$
38+
- pkg/common/concurrentviper/generated\.go$
3539
formatters:
3640
enable:
3741
- gofumpt

cmd/osde2e/provision/cmd.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package provision
22

33
import (
4+
"errors"
45
"fmt"
56

67
"github.com/openshift/osde2e/cmd/osde2e/common"
@@ -80,7 +81,6 @@ func init() {
8081
_ = viper.BindPFlag(config.Tests.OnlyHealthCheckNodes, Cmd.PersistentFlags().Lookup("only-health-check-nodes"))
8182
}
8283

83-
//nolint:gocyclo
8484
func run(cmd *cobra.Command, argv []string) error {
8585
var err error
8686
if err = common.LoadConfigs(args.configString, "", args.secretLocations); err != nil {
@@ -92,5 +92,8 @@ func run(cmd *cobra.Command, argv []string) error {
9292
}
9393

9494
_, err = clusterutil.Provision(provider)
95-
return err
95+
if err != nil && !errors.Is(err, clusterutil.ErrReserveFull) {
96+
return err
97+
}
98+
return nil
9699
}

internal/sanitizer/sanitizer.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -163,12 +163,14 @@ func (s *Sanitizer) sanitizeContent(content, source string, timestamp time.Time)
163163

164164
// Perform audit logging asynchronously to avoid blocking
165165
if s.auditLog != nil && (matchCount > 0 || !s.config.SkipAuditOnNoMatch) {
166-
go s.auditLog.Log(AuditEntry{
167-
Timestamp: timestamp,
168-
Source: source,
169-
RulesApplied: rulesApplied,
170-
MatchCount: matchCount,
171-
})
166+
go func() {
167+
_ = s.auditLog.Log(AuditEntry{
168+
Timestamp: timestamp,
169+
Source: source,
170+
RulesApplied: rulesApplied,
171+
MatchCount: matchCount,
172+
})
173+
}()
172174
}
173175

174176
return result, nil

pkg/common/aws/s3.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,12 +140,12 @@ type S3UploadResult struct {
140140
// Upload is automatically enabled when LOG_BUCKET is set.
141141
// Reuses the global CcsAwsSession for AWS credentials and session management.
142142
// The component parameter is used to organize artifacts in S3 (e.g., "osd-example-operator").
143+
//
144+
// TODO: Refactor to use dependency injection instead of viper globals.
145+
// Should accept (bucket, region, component string) parameters for better testability
146+
// and reusability. Caller should check config and decide whether to upload.
143147
func NewS3Uploader(component string) (*S3Uploader, error) {
144148
bucket := viper.GetString(config.Tests.LogBucket)
145-
if bucket == "" {
146-
// S3 upload disabled - no bucket configured
147-
return nil, nil
148-
}
149149

150150
// Ensure region is set (default to us-east-1)
151151
if viper.GetString(config.AWSRegion) == "" {

pkg/common/aws/s3_test.go

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -68,18 +68,6 @@ func TestBuildS3Key(t *testing.T) {
6868
}
6969
}
7070

71-
func TestNewS3Uploader_Disabled(t *testing.T) {
72-
viper.Set(config.Tests.LogBucket, "")
73-
74-
uploader, err := NewS3Uploader("test-component")
75-
if err != nil {
76-
t.Errorf("NewS3Uploader() with disabled config returned error: %v", err)
77-
}
78-
if uploader != nil {
79-
t.Error("NewS3Uploader() should return nil when LOG_BUCKET is empty")
80-
}
81-
}
82-
8371
func TestBuildBaseKey(t *testing.T) {
8472
tests := []struct {
8573
key string

pkg/common/cluster/clusterutil.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -569,9 +569,8 @@ func Provision(provider spi.Provider) (*spi.Cluster, error) {
569569
if err != nil {
570570
if errors.Is(err, ErrReserveFull) {
571571
log.Printf("Reserve full, exiting without provisioning")
572-
return nil, nil
573572
}
574-
return nil, fmt.Errorf("failed to set up or retrieve cluster: %v", err)
573+
return nil, fmt.Errorf("failed to set up or retrieve cluster: %w", err)
575574
}
576575

577576
viper.Set(config.Cluster.ID, cluster.ID())

pkg/common/concurrentviper/generated.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// nolint
21
package concurrentviper
32

43
import (

pkg/common/providers/ocmprovider/cluster.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ func (o *OCMProvider) IsValidClusterName(clusterName string) (bool, error) {
6464
}
6565

6666
// LaunchCluster setups an new cluster using the OSD API and returns it's ID.
67-
// nolint:gocyclo
67+
//
68+
//nolint:gocyclo
6869
func (o *OCMProvider) LaunchCluster(clusterName string) (string, error) {
6970
flavourID := getFlavour()
7071
skuID := getSKU()

pkg/e2e/e2e.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -249,27 +249,27 @@ func (o *E2EOrchestrator) Report(ctx context.Context) error {
249249

250250
runner.ReportClusterInstallLogs(o.provider)
251251

252-
// Upload test artifacts to S3 if bucket set
253-
if viper.GetString(config.Tests.LogBucket) != "" {
254-
if err := o.uploadToS3(); err != nil {
255-
log.Printf("S3 upload failed: %v", err)
256-
// Don't fail the overall report phase for S3 upload errors
257-
}
252+
// Upload test artifacts to S3 if bucket configured
253+
if err := o.uploadToS3(); err != nil {
254+
log.Printf("S3 upload failed: %v", err)
255+
// Don't fail the overall report phase for S3 upload errors
258256
}
259257

260258
return nil
261259
}
262260

263261
// uploadToS3 uploads the report directory contents to S3.
264262
func (o *E2EOrchestrator) uploadToS3() error {
263+
// Check if S3 bucket is configured
264+
if viper.GetString(config.Tests.LogBucket) == "" {
265+
return nil // S3 upload not configured, skip
266+
}
267+
265268
component := deriveComponentFromTestImage()
266269
uploader, err := aws.NewS3Uploader(component)
267270
if err != nil {
268271
return fmt.Errorf("failed to create S3 uploader: %w", err)
269272
}
270-
if uploader == nil {
271-
return nil // S3 upload not enabled
272-
}
273273

274274
reportDir := viper.GetString(config.ReportDir)
275275
if reportDir == "" {

test/sdn_migration/sdn_migration_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,10 +264,10 @@ func runTerraformCommand(command string) (map[string]tfexec.OutputMeta, error) {
264264
if err != nil {
265265
return nil, fmt.Errorf("terraform destroy failed: %v", err.Error())
266266
}
267+
return map[string]tfexec.OutputMeta{}, nil
267268
default:
268269
return nil, fmt.Errorf("unknown command: %s", command)
269270
}
270-
return nil, nil
271271
}
272272

273273
func cluterOperatorHealthCheck(ctx context.Context, clusterClient *openshiftclient.Client, logger logr.Logger) error {

0 commit comments

Comments
 (0)