Skip to content

Commit b7d349d

Browse files
committed
chore: fix golangci-lint violations across codebase
Add golangci-lint to CI pipeline and resolve linting issues: - Add golangci-lint target to Makefile for CI enforcement - Disable fieldalignment checker in .golangci.yml - Fix unchecked error returns with proper error handling - Replace fmt.Fprintf + os.Exit patterns with log.Fatal - Add proper defer cleanup with error checking - Fix unused parameters and mark with nolint directives - Improve error message formatting consistency - Remove unused context parameters - Rename FossaError to Error for naming convention - Fix constant naming (FossaTeamAdmin) and type declarations - Replace fmt.Printf with log.Printf for consistency - Address gosimple and staticcheck warnings This improves code quality and establishes baseline for automated linting in the CI pipeline. Signed-off-by: Robert Kielty <[email protected]>
1 parent 68cd5bd commit b7d349d

File tree

11 files changed

+85
-60
lines changed

11 files changed

+85
-60
lines changed

.golangci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ linters:
2121
govet:
2222
disable:
2323
- shadow
24+
- fieldalignment
2425
enable-all: true
2526
misspell:
2627
locale: US

Makefile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,12 @@ ci-local:
260260
else \
261261
echo "⚠️ staticcheck not installed. Run: go install honnef.co/go/tools/cmd/staticcheck@latest"; \
262262
fi
263+
@echo "→ Running golangci-lint..."
264+
@if command -v golangci-lint >/dev/null 2>&1; then \
265+
golangci-lint run ./...; \
266+
else \
267+
echo "⚠️ golangci-lint not installed. Run: go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest"; \
268+
fi
263269
@echo "→ Running tests with race detector..."
264270
@go test -race -coverprofile=coverage.out -covermode=atomic ./...
265271
@echo "→ Coverage report:"

cmd/bootstrap/main.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,12 @@ func copyFile(src, dst string) error {
9494
if err != nil {
9595
return err
9696
}
97-
defer source.Close()
97+
defer func(source *os.File) {
98+
err := source.Close()
99+
if err != nil {
100+
log.Printf("warning: failed to close file %s: %v", src, err)
101+
}
102+
}(source)
98103

99104
destination, err := os.Create(dst)
100105
if err != nil {

cmd/fossa/main.go

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package main
22

33
import (
44
"fmt"
5+
"log"
56
"maintainerd/plugins/fossa"
67
"os"
78
)
@@ -13,16 +14,14 @@ const (
1314
func main() {
1415
token := os.Getenv(apiTokenEnvVar)
1516
if token == "" {
16-
fmt.Fprintf(os.Stderr, "please set $%s\n", apiTokenEnvVar)
17-
os.Exit(1)
17+
log.Fatalf("please set $%s\n", apiTokenEnvVar)
1818
}
1919
fossaClient := fossa.NewClient(token)
2020

2121
teams, err := fossaClient.FetchTeams()
2222

2323
if err != nil {
24-
fmt.Fprintf(os.Stderr, "error fetching teams: %v\n", err)
25-
os.Exit(1)
24+
log.Fatalf("error fetching teams: %v\n", err)
2625
}
2726
fmt.Println("Your teams:")
2827
for _, t := range teams {
@@ -36,22 +35,19 @@ func main() {
3635

3736
// 2) pick a team ID on the CLI
3837
if len(os.Args) < 2 {
39-
fmt.Fprintf(os.Stderr, "usage: %s <teamName>\n", os.Args[0])
40-
os.Exit(1)
38+
log.Fatalf("usage: %s <teamName>\n", os.Args[0])
4139
}
4240
teamName := os.Args[1]
4341

4442
teamID, err := fossaClient.GetTeamId(teams, teamName)
4543

4644
if err != nil {
47-
fmt.Fprintf(os.Stderr, "error fetching team: %v\n", err)
48-
os.Exit(1)
45+
log.Fatalf("error fetching team: %v", err)
4946
}
5047

5148
emails, err := fossaClient.FetchTeamUserEmails(teamID)
5249
if err != nil {
53-
fmt.Fprintf(os.Stderr, "error fetching users: %v\n", err)
54-
os.Exit(1)
50+
log.Fatalf("error fetching users: %v", err)
5551
}
5652

5753
fmt.Println("Team members’ emails:")

db/bootstrap.go

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,7 @@ func BootstrapSQLite(dbPath, spreadsheetID, worksheetCredentialsPath, fossaToken
100100
return db, nil
101101
}
102102

103-
// Reads the readRange data from spreadsheetID inserts it into db
104-
// The readRange from the worksheet MUST include the header row
103+
// Reads data from spreadsheetID inserts it into db.
105104
func loadMaintainersAndProjects(db *gorm.DB, spreadsheetID, credentialsPath string) error {
106105
ctx := context.Background()
107106

@@ -113,12 +112,14 @@ func loadMaintainersAndProjects(db *gorm.DB, spreadsheetID, credentialsPath stri
113112

114113
if err != nil {
115114
log.Fatalf("maintainerd: backend: loadMaintainersAndProjects: unable to retrieve Sheets client: %v", err)
115+
return err
116116
}
117117

118118
rows, err := readSheetRows(ctx, srv, spreadsheetID)
119119

120120
if err != nil {
121121
log.Fatalf("maintainerd-backend: loadMaintainersAndProjects - readSheetRows: %v", err)
122+
return err
122123
}
123124

124125
var currentMaintainerRef string
@@ -154,9 +155,15 @@ func loadMaintainersAndProjects(db *gorm.DB, spreadsheetID, credentialsPath stri
154155
log.Printf("DEBUG, processing maintainer %s, missing fields %v \n", row[MaintainerNameHdr], missingMaintainerFields)
155156
var parent model.Project
156157
if parentName := row[ParentProjectHdr]; parentName != "" {
157-
parent = model.Project{}
158158
if err := db.Where("name = ?", parentName).
159159
First(&parent).Error; err != nil {
160+
if errors.Is(err, gorm.ErrRecordNotFound) {
161+
log.Printf("WARN, parent project '%s' not found for project '%s', importing without parent", parentName, row[ProjectHdr])
162+
} else {
163+
log.Printf("ERR, error looking up parent project '%s' for project '%s': %v", parentName, row[ProjectHdr], err)
164+
}
165+
} else {
166+
log.Printf("INFO, project '%s' will be associated with parent project '%s' (ID: %d)", row[ProjectHdr], parentName, parent.ID)
160167
}
161168
}
162169
currentMaintainerRef = row[MaintainerFileRefHdr]
@@ -181,11 +188,11 @@ func loadMaintainersAndProjects(db *gorm.DB, spreadsheetID, credentialsPath stri
181188
}
182189
}
183190
if err := tx.FirstOrCreate(&project, model.Project{Name: project.Name}).Error; err != nil {
184-
return fmt.Errorf("maintainerd-backend: loadMaintainersAndProjects - failed calling FirstOrCreate on project %v: error %v", project, err)
191+
return fmt.Errorf("ERR, loadMaintainersAndProjects - failed calling FirstOrCreate on project %v: error %v", project, err)
185192
}
186193
company := model.Company{Name: company}
187194
if err := tx.FirstOrCreate(&company, model.Company{Name: company.Name}).Error; err != nil {
188-
return fmt.Errorf("maintainerd-backend: loadMaintainersAndProjects - failed calling FirstOrCreate on company %v: error %v", company, err)
195+
return fmt.Errorf("ERR, loadMaintainersAndProjects - failed calling FirstOrCreate on company %v: error %v", company, err)
189196
}
190197
maintainer := model.Maintainer{
191198
Name: name,
@@ -196,14 +203,14 @@ func loadMaintainersAndProjects(db *gorm.DB, spreadsheetID, credentialsPath stri
196203
MaintainerStatus: model.ActiveMaintainer,
197204
}
198205
if err := tx.FirstOrCreate(&maintainer, model.Maintainer{Email: maintainer.Email}).Error; err != nil {
199-
return fmt.Errorf("maintainerd-backend: loadMaintainersAndProjects - failed calling FirstOrCreate on maintainer %v: error %v", maintainer, err)
206+
return fmt.Errorf("ERR, loadMaintainersAndProjects - failed calling FirstOrCreate on maintainer %v: error %v", maintainer, err)
200207
}
201208
// Ensure the association (in case the maintainer existed already)
202209
return tx.Model(&maintainer).
203210
Association("Projects").
204211
Append(&project)
205212
}); err != nil {
206-
log.Printf("TX not committed, row skipped %v : error %v ", row, err)
213+
log.Printf("WARN, loadMaintainersAndProjects Database transaction not committed, row skipped %v : error %v ", row, err)
207214
}
208215
}
209216
return nil
@@ -336,8 +343,10 @@ func CreateServiceTeamsForUser(
336343
var teams []*model.ServiceTeam
337344
var errMessages []string
338345
s := NewSQLStore(db)
339-
projects, _ := s.GetProjectMapByName()
340-
346+
projects, err := s.GetProjectMapByName()
347+
if err != nil {
348+
return nil, fmt.Errorf("CreateServiceTeamsForUser: GetProjectMapByName failed to get project map: %v", err)
349+
}
341350
for _, team := range teamUsers {
342351
if project, ok := projects[team.Team.Name]; ok {
343352
st := &model.ServiceTeam{
@@ -389,7 +398,7 @@ func MapFossaUserCollaborator(db *gorm.DB, email string, github string, user fos
389398
Where("LOWER(git_hub_account) = ?", strings.ToLower(github)).
390399
FirstOrCreate(&c).Error; err == nil {
391400
return &c
392-
} else if err != nil {
401+
} else {
393402
return nil
394403
}
395404
}
@@ -398,12 +407,10 @@ func MapFossaUserCollaborator(db *gorm.DB, email string, github string, user fos
398407
Where("LOWER(email) = ?", strings.ToLower(email)).
399408
FirstOrCreate(&c).Error; err == nil {
400409
return &c
401-
} else if err != nil {
410+
} else {
402411
log.Printf("mapFossaUserCollaborator: error creating collaborator: %s, %+v %v", email, c, err)
403412
return nil
404413
}
405-
406-
return &c
407414
}
408415

409416
// MapFossaUserToMaintainer attempts to match a FOSSA user to a registered Maintainer.
@@ -526,7 +533,7 @@ func LinkServiceUserToTeam(
526533
}
527534

528535
func FirstOrCreateServiceUser(db *gorm.DB, user fossa.User) (*model.ServiceUser, error) {
529-
var fossaService = model.Service{Model: gorm.Model{ID: 1}, Name: "FOSSA"}
536+
var fossaService = model.Service{Model: gorm.Model{ID: 1}}
530537

531538
var su model.ServiceUser
532539

db/store_impl.go

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func (s *SQLStore) GetMaintainersByProject(projectID uint) ([]model.Maintainer,
5757
Preload("Maintainers.Company").
5858
First(&project, projectID).Error
5959
if err != nil {
60-
if err == gorm.ErrRecordNotFound {
60+
if errors.Is(err, gorm.ErrRecordNotFound) {
6161
return nil, ErrProjectNotFound
6262
}
6363
return nil, err
@@ -147,25 +147,15 @@ func (s *SQLStore) GetProjectMapByName() (map[string]model.Project, error) {
147147
return projectsByName, nil
148148
}
149149

150-
func (s *SQLStore) LogAuditEvent(logger *zap.SugaredLogger, event model.AuditLog) error {
150+
func (s *SQLStore) LogAuditEvent(logger *zap.SugaredLogger, event model.AuditLog) {
151151
if event.Message == "" {
152152
event.Message = event.Action
153153
}
154154

155155
err := s.db.WithContext(context.Background()).Create(&event).Error
156156
if err != nil {
157-
logger.Errorf("failed to write audit log: %v", err)
158-
return err
157+
logger.Errorf("failed to write %v audit log: %v", event, err)
159158
}
160-
161-
logger.Infow("audit log recorded",
162-
"project_id", event.ProjectID,
163-
"maintainer_id", event.MaintainerID,
164-
"service_id", event.ServiceID,
165-
"action", event.Action,
166-
"message", event.Message,
167-
)
168-
return nil
169159
}
170160

171161
// CreateServiceTeam creates or retrieves a service team entry in the database based on the provided project and service details.

model/main.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ package model
33
import (
44
"database/sql/driver"
55
"fmt"
6-
"gorm.io/gorm"
76
"net/url"
87
"time"
8+
9+
"gorm.io/gorm"
910
)
1011

1112
type MaintainerStatus string
@@ -80,7 +81,7 @@ func (m Maturity) IsValid() bool {
8081
// Optionally, a Maintainer
8182
//
8283
// has a Company Affiliation
83-
// TODO kubernetes specific may or may not have have voting rights on a Project,
84+
// Fot kubernetes specifically, a maintainer or may not have voting rights on a Project,
8485
// has a status of Active, Emeritus or Retired
8586
type Maintainer struct {
8687
gorm.Model

onboarding/github_mock.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,17 +44,25 @@ func (m *MockGitHubTransport) RoundTrip(req *http.Request) (*http.Response, erro
4444

4545
// Capture comment creation
4646
if req.Method == "POST" && strings.Contains(req.URL.Path, "/issues/") && strings.HasSuffix(req.URL.Path, "/comments") {
47-
body, _ := io.ReadAll(req.Body)
47+
body, err := io.ReadAll(req.Body)
48+
if err != nil {
49+
return nil, err
50+
}
4851
req.Body = io.NopCloser(bytes.NewReader(body))
4952

5053
var comment github.IssueComment
51-
json.Unmarshal(body, &comment)
54+
if json.Unmarshal(body, &comment) != nil {
55+
return nil, err
56+
}
5257

5358
// Parse owner, repo, issue number from URL
5459
// URL format: /repos/{owner}/{repo}/issues/{issue_number}/comments
5560
parts := strings.Split(req.URL.Path, "/")
5661
if len(parts) >= 6 {
57-
issueNum, _ := strconv.Atoi(parts[5])
62+
issueNum, err := strconv.Atoi(parts[5])
63+
if err != nil {
64+
return nil, err
65+
}
5866
capture := GitHubCommentCapture{
5967
Owner: parts[2],
6068
Repo: parts[3],

0 commit comments

Comments
 (0)