diff --git a/.golangci.yml b/.golangci.yml index fb3d107703d..bf4c9a0ebff 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -24,6 +24,7 @@ linters: - bidichk - bodyclose - canonicalheader + - containedctx - contextcheck - copyloopvar - decorder @@ -33,7 +34,10 @@ linters: - errcheck - errchkjson - errname + - errorlint + - exhaustive - fatcontext + - forcetypeassert - gci - ginkgolinter - gocheckcompilerdirectives @@ -65,6 +69,8 @@ linters: - misspell - musttag - nakedret + - nilerr + - noctx - nolintlint - nosprintfhostport - perfsprint @@ -85,6 +91,7 @@ linters: - tenv - testableexamples - testifylint + - tparallel - typecheck - unconvert - unparam @@ -93,16 +100,12 @@ linters: - wastedassign - whitespace - zerologlint - # - containedctx # - cyclop # - depguard # - dupword # - err113 - # - errorlint - # - exhaustive # - exhaustruct # - forbidigo - # - forcetypeassert # - funlen # - gochecknoglobals # - gochecknoinits @@ -114,16 +117,13 @@ linters: # - maintidx # - mnd # - nestif - # - nilerr # - nilnil # - nlreturn - # - noctx # - nonamedreturns # - paralleltest # - tagliatelle # - testpackage # - thelper - # - tparallel # - varnamelen # - wrapcheck # - wsl diff --git a/cmd/ci-reporter/cmd/github.go b/cmd/ci-reporter/cmd/github.go index d756e58a518..ca70e60732f 100644 --- a/cmd/ci-reporter/cmd/github.go +++ b/cmd/ci-reporter/cmd/github.go @@ -36,7 +36,7 @@ var githubCmd = &cobra.Command{ Long: "CI-Signal reporter that generates only a github report.", PreRun: setGithubConfig, RunE: func(cmd *cobra.Command, args []string) error { - return RunReport(cfg, &CIReporters{GithubReporter{}}) + return RunReport(cmd.Context(), cfg, &CIReporters{GithubReporter{}}) }, } @@ -75,7 +75,7 @@ func (r GithubReporter) GetCIReporterHead() CIReporterInfo { } // CollectReportData implementation from CIReporter. -func (r GithubReporter) CollectReportData(cfg *Config) ([]*CIReportRecord, error) { +func (r GithubReporter) CollectReportData(ctx context.Context, cfg *Config) ([]*CIReportRecord, error) { // set filter configuration denyListFilter := map[FilteredFieldName][]FilteredListVal{} allowListFilter := map[FilteredFieldName][]FilteredListVal{ @@ -88,7 +88,7 @@ func (r GithubReporter) CollectReportData(cfg *Config) ([]*CIReportRecord, error allowListFilter[FilteredFieldName("K8s Release")] = []FilteredListVal{FilteredListVal(cfg.ReleaseVersion)} } // request github projectboard data - githubReportData, err := GetGithubReportData(*cfg, denyListFilter, allowListFilter) + githubReportData, err := GetGithubReportData(ctx, *cfg, denyListFilter, allowListFilter) if err != nil { return nil, fmt.Errorf("getting GitHub report data: %w", err) } @@ -211,13 +211,13 @@ type ( ) // GetGithubReportData used to request the raw report data from github. -func GetGithubReportData(cfg Config, denyListFieldFilter, allowListFieldFilter map[FilteredFieldName][]FilteredListVal) ([]*TransformedProjectBoardItem, error) { +func GetGithubReportData(ctx context.Context, cfg Config, denyListFieldFilter, allowListFieldFilter map[FilteredFieldName][]FilteredListVal) ([]*TransformedProjectBoardItem, error) { // lookup project board information var queryCiSignalProjectBoard ciSignalProjectBoardGraphQLQuery variablesProjectBoardFields := map[string]interface{}{ "projectBoardID": githubv4.ID(ciSignalProjectBoardID), } - if err := cfg.GithubClient.Query(context.Background(), &queryCiSignalProjectBoard, variablesProjectBoardFields); err != nil { + if err := cfg.GithubClient.Query(ctx, &queryCiSignalProjectBoard, variablesProjectBoardFields); err != nil { return nil, err } diff --git a/cmd/ci-reporter/cmd/root.go b/cmd/ci-reporter/cmd/root.go index 869d6748131..962e963bf62 100644 --- a/cmd/ci-reporter/cmd/root.go +++ b/cmd/ci-reporter/cmd/root.go @@ -28,6 +28,7 @@ import ( "github.com/shurcooL/githubv4" "github.com/spf13/cobra" "github.com/tj/go-spin" + "golang.org/x/net/context" ) var rootCmd = &cobra.Command{ @@ -39,7 +40,7 @@ var rootCmd = &cobra.Command{ // all available reporters are used by default that are used to generate the report // CLI sub commands can be used to specify a specific reporter selectedReporters := AllImplementedReporters - return RunReport(cfg, &selectedReporters) + return RunReport(cmd.Context(), cfg, &selectedReporters) }, } @@ -68,7 +69,7 @@ func init() { } // RunReport used to execute. -func RunReport(cfg *Config, reporters *CIReporters) error { +func RunReport(ctx context.Context, cfg *Config, reporters *CIReporters) error { go func() { s := spin.New() for { @@ -78,7 +79,7 @@ func RunReport(cfg *Config, reporters *CIReporters) error { }() // collect data from filtered reporters - reports, err := reporters.CollectReportDataFromReporters(cfg) + reports, err := reporters.CollectReportDataFromReporters(ctx, cfg) if err != nil { return err } @@ -137,7 +138,7 @@ type CIReporter interface { // GetCIReporterHead sets meta information which is used to differentiate reporters GetCIReporterHead() CIReporterInfo // CollectReportData is used to request / collect all report data - CollectReportData(*Config) ([]*CIReportRecord, error) + CollectReportData(context.Context, *Config) ([]*CIReportRecord, error) } // CIReporters used to specify multiple CIReports, type gets extended by helper functions to collect and visualize report data. @@ -147,7 +148,7 @@ type CIReporters []CIReporter var AllImplementedReporters = CIReporters{GithubReporter{}, TestgridReporter{}} // SearchReporter used to filter a implemented reporter by name. -func SearchReporter(reporterName string) (CIReporter, error) { +func SearchReporter(ctx context.Context, reporterName string) (CIReporter, error) { var reporter CIReporter reporterFound := false for _, r := range AllImplementedReporters { @@ -164,13 +165,13 @@ func SearchReporter(reporterName string) (CIReporter, error) { } // CollectReportDataFromReporters used to collect data for multiple reporters. -func (r *CIReporters) CollectReportDataFromReporters(cfg *Config) (*CIReportDataFields, error) { +func (r *CIReporters) CollectReportDataFromReporters(ctx context.Context, cfg *Config) (*CIReportDataFields, error) { collectedReports := CIReportDataFields{} for i := range *r { reporters := *r reporter := reporters[i] reporterHead := reporter.GetCIReporterHead() - reportData, err := reporter.CollectReportData(cfg) + reportData, err := reporter.CollectReportData(ctx, cfg) if err != nil { return nil, err } diff --git a/cmd/ci-reporter/cmd/testgrid.go b/cmd/ci-reporter/cmd/testgrid.go index 45a73cab42e..4b7568033f1 100644 --- a/cmd/ci-reporter/cmd/testgrid.go +++ b/cmd/ci-reporter/cmd/testgrid.go @@ -17,6 +17,7 @@ limitations under the License. package cmd import ( + "context" "errors" "fmt" "time" @@ -33,7 +34,7 @@ var testgridCmd = &cobra.Command{ Long: "CI-Signal reporter that generates only a testgrid report.", PreRun: setGithubConfig, RunE: func(cmd *cobra.Command, args []string) error { - return RunReport(cfg, &CIReporters{TestgridReporter{}}) + return RunReport(cmd.Context(), cfg, &CIReporters{TestgridReporter{}}) }, } @@ -54,8 +55,8 @@ func (r TestgridReporter) GetCIReporterHead() CIReporterInfo { } // CollectReportData implementation from CIReporter. -func (r TestgridReporter) CollectReportData(cfg *Config) ([]*CIReportRecord, error) { - testgridReportData, err := GetTestgridReportData(*cfg) +func (r TestgridReporter) CollectReportData(ctx context.Context, cfg *Config) ([]*CIReportRecord, error) { + testgridReportData, err := GetTestgridReportData(ctx, *cfg) if err != nil { return nil, err } @@ -80,7 +81,7 @@ func (r TestgridReporter) CollectReportData(cfg *Config) ([]*CIReportRecord, err } // GetTestgridReportData used to request the raw report data from testgrid. -func GetTestgridReportData(cfg Config) (testgrid.DashboardData, error) { +func GetTestgridReportData(ctx context.Context, cfg Config) (testgrid.DashboardData, error) { testgridDashboardNames := []testgrid.DashboardName{"sig-release-master-blocking", "sig-release-master-informing"} if cfg.ReleaseVersion != "" { testgridDashboardNames = append(testgridDashboardNames, []testgrid.DashboardName{ @@ -90,7 +91,7 @@ func GetTestgridReportData(cfg Config) (testgrid.DashboardData, error) { } dashboardData := testgrid.DashboardData{} for i := range testgridDashboardNames { - d, err := testgrid.ReqTestgridDashboardSummary(testgridDashboardNames[i]) + d, err := testgrid.ReqTestgridDashboardSummary(ctx, testgridDashboardNames[i]) if err != nil { if errors.Is(err, testgrid.ErrDashboardNotFound) { logrus.Warn(fmt.Sprintf("%v for project board %s", err.Error(), testgridDashboardNames[i])) diff --git a/gcb/gcb_test.go b/gcb/gcb_test.go index 8e1de52e00b..1a8697a9e0e 100644 --- a/gcb/gcb_test.go +++ b/gcb/gcb_test.go @@ -156,6 +156,8 @@ func TestDirForJobType(t *testing.T) { }, } { t.Run(tc.name, func(t *testing.T) { + t.Parallel() + mock := &gcbfakes.FakeImpl{} sut := New() sut.impl = mock diff --git a/pkg/binary/binary.go b/pkg/binary/binary.go index a7fac481b9a..76d8085d2ef 100644 --- a/pkg/binary/binary.go +++ b/pkg/binary/binary.go @@ -169,7 +169,7 @@ func (b *Binary) ContainsStrings(s ...string) (match bool, err error) { // Read each rune from the binary file r, _, err := in.ReadRune() if err != nil { - if err != io.EOF { + if !errors.Is(err, io.EOF) { return match, fmt.Errorf("while reading binary data: %w", err) } return false, nil diff --git a/pkg/build/build_test.go b/pkg/build/build_test.go index 9e14cdbb266..c6a0eaa07a7 100644 --- a/pkg/build/build_test.go +++ b/pkg/build/build_test.go @@ -21,6 +21,7 @@ import ( ) func TestBuildDirFromRepoRoot(t *testing.T) { + t.Parallel() testCases := []struct { name string instance *Instance diff --git a/pkg/notes/document/document.go b/pkg/notes/document/document.go index b8c12e956f7..504ef3e3aa9 100644 --- a/pkg/notes/document/document.go +++ b/pkg/notes/document/document.go @@ -533,6 +533,7 @@ func mapKind(kind notes.Kind) notes.Kind { } func prettyKind(kind notes.Kind) string { + //nolint:exhaustive // all cases are covered by default switch kind { case notes.KindAPIChange: return "API Change" diff --git a/pkg/notes/notes.go b/pkg/notes/notes.go index 24f81228ec5..dc1496a75fa 100644 --- a/pkg/notes/notes.go +++ b/pkg/notes/notes.go @@ -215,7 +215,7 @@ type Result struct { type Gatherer struct { client github.Client - context context.Context + context context.Context //nolint:containedctx // contained context is intentional options *options.Options MapProviders []*MapProvider } @@ -787,7 +787,7 @@ func (g *Gatherer) ReleaseNoteForPullRequest(prNr int) (*ReleaseNote, error) { func (g *Gatherer) notesForCommit(commit *gogithub.RepositoryCommit) (*Result, error) { prs, err := g.prsFromCommit(commit) if err != nil { - if err == errNoPRIDFoundInCommitMessage || err == errNoPRFoundForCommitSHA { + if errors.Is(err, errNoPRIDFoundInCommitMessage) || errors.Is(err, errNoPRFoundForCommitSHA) { logrus.Debugf( "No matches found when parsing PR from commit SHA %s", commit.GetSHA(), diff --git a/pkg/notes/notes_gatherer_test.go b/pkg/notes/notes_gatherer_test.go index 33b6cdc32b6..a9aadca783a 100644 --- a/pkg/notes/notes_gatherer_test.go +++ b/pkg/notes/notes_gatherer_test.go @@ -42,6 +42,7 @@ func TestMain(m *testing.M) { } func TestListCommits(t *testing.T) { + t.Parallel() const always = -1 zeroTime := &github.Timestamp{} @@ -236,6 +237,7 @@ func TestListCommits(t *testing.T) { } func TestGatherNotes(t *testing.T) { + t.Parallel() type getPullRequestStub func(context.Context, string, string, int) (*github.PullRequest, *github.Response, error) type listPullRequestsWithCommitStub func(context.Context, string, string, string, *github.ListOptions) ([]*github.PullRequest, *github.Response, error) diff --git a/pkg/notes/notes_map.go b/pkg/notes/notes_map.go index a009381f500..3b074b8e457 100644 --- a/pkg/notes/notes_map.go +++ b/pkg/notes/notes_map.go @@ -68,7 +68,7 @@ func ParseReleaseNotesMap(mapPath string) (*[]ReleaseNotesMap, error) { for { noteMap := ReleaseNotesMap{} - if err := decoder.Decode(¬eMap); err == io.EOF { + if err := decoder.Decode(¬eMap); errors.Is(err, io.EOF) { break } else if err != nil { return nil, fmt.Errorf("decoding note map: %w", err) diff --git a/pkg/notes/notes_v2.go b/pkg/notes/notes_v2.go index c99d6cd66d3..1eae888f54e 100644 --- a/pkg/notes/notes_v2.go +++ b/pkg/notes/notes_v2.go @@ -281,7 +281,7 @@ func (g *Gatherer) listLeftParentCommits(opts *options.Options) ([]*commitPrPair // Find and collect PR number from commit message prNums, err := prsNumForCommitFromMessage(commitPointer.Message) - if err == errNoPRIDFoundInCommitMessage { + if errors.Is(err, errNoPRIDFoundInCommitMessage) { logrus.WithFields(logrus.Fields{ "sha": hashString, }).Debug("no associated PR found") diff --git a/pkg/release/publish.go b/pkg/release/publish.go index cdd2fc234d8..521d97b9f68 100644 --- a/pkg/release/publish.go +++ b/pkg/release/publish.go @@ -276,6 +276,7 @@ func (p *Publisher) VerifyLatestUpdate( gcsVersion, err := p.client.GSUtilOutput("cat", publishFileDst) if err != nil { logrus.Infof("%s does not exist but will be created", publishFileDst) + //nolint:nilerr // returning nil is intentional return true, nil } diff --git a/pkg/testgrid/testgrid-scraper.go b/pkg/testgrid/testgrid-scraper.go index aad24bd0238..267a18d52cd 100644 --- a/pkg/testgrid/testgrid-scraper.go +++ b/pkg/testgrid/testgrid-scraper.go @@ -17,6 +17,7 @@ limitations under the License. package testgrid import ( + "context" "encoding/json" "errors" "fmt" @@ -37,14 +38,14 @@ type SummaryLookup struct { // ReqTestgridDashboardSummaries this function requests multiple testgrid summaries concurrently // This function implements a concurrency pattern to send http requests concurrently. -func ReqTestgridDashboardSummaries(dashboardNames []DashboardName) (DashboardData, error) { +func ReqTestgridDashboardSummaries(ctx context.Context, dashboardNames []DashboardName) (DashboardData, error) { // Worker requestData := func(done <-chan interface{}, dashboardNames ...DashboardName) <-chan SummaryLookup { summaryLookups := make(chan SummaryLookup) go func() { defer close(summaryLookups) for _, dashboardName := range dashboardNames { - summary, err := ReqTestgridDashboardSummary(dashboardName) + summary, err := ReqTestgridDashboardSummary(ctx, dashboardName) select { case <-done: return @@ -80,8 +81,15 @@ type NotFound error var ErrDashboardNotFound NotFound = errors.New("testgrid dashboard not found") // ReqTestgridDashboardSummary used to retrieve summary information about a testgrid dashboard. -func ReqTestgridDashboardSummary(dashboardName DashboardName) (JobData, error) { - resp, err := http.Get(fmt.Sprintf("https://testgrid.k8s.io/%s/summary", dashboardName)) +func ReqTestgridDashboardSummary(ctx context.Context, dashboardName DashboardName) (JobData, error) { + url := fmt.Sprintf("https://testgrid.k8s.io/%s/summary", dashboardName) + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, http.NoBody) + if err != nil { + return nil, fmt.Errorf("create new request: %w", err) + } + + resp, err := http.DefaultClient.Do(req) if err != nil { return nil, fmt.Errorf("request remote content: %w", err) } diff --git a/pkg/testgrid/testgrid-scraper_test.go b/pkg/testgrid/testgrid-scraper_test.go index 3bcbc49140f..977c03eade0 100644 --- a/pkg/testgrid/testgrid-scraper_test.go +++ b/pkg/testgrid/testgrid-scraper_test.go @@ -17,6 +17,7 @@ limitations under the License. package testgrid import ( + "context" "fmt" "testing" @@ -35,7 +36,7 @@ func TestRequestTestgridSummaryPos(t *testing.T) { for _, dashboardName := range posDashboardNames { // When - summary, err := ReqTestgridDashboardSummary(dashboardName) + summary, err := ReqTestgridDashboardSummary(context.Background(), dashboardName) // Then require.NoError(t, err) @@ -52,7 +53,7 @@ func TestRequestTestgridSummaryNeg(t *testing.T) { for _, dashboardName := range negDashboardNames { // When - summary, err := ReqTestgridDashboardSummary(dashboardName) + summary, err := ReqTestgridDashboardSummary(context.Background(), dashboardName) // Then require.Error(t, err) @@ -65,7 +66,7 @@ func TestRequestTestgridSummariesPos(t *testing.T) { // positive dashboard names // When - data, err := ReqTestgridDashboardSummaries(posDashboardNames) + data, err := ReqTestgridDashboardSummaries(context.Background(), posDashboardNames) // Then require.NoError(t, err) @@ -77,7 +78,7 @@ func TestRequestTestgridSummariesNeg(t *testing.T) { // negative dashboard names // When - data, err := ReqTestgridDashboardSummaries(negDashboardNames) + data, err := ReqTestgridDashboardSummaries(context.Background(), negDashboardNames) // Then require.Error(t, err) @@ -89,7 +90,7 @@ func TestRequestTestgridSummariesPosNeg(t *testing.T) { // Request positive and negative dashboard names, expect to get an error and receive positive dashboard name summaries // When - data, err := ReqTestgridDashboardSummaries(append(negDashboardNames, posDashboardNames...)) + data, err := ReqTestgridDashboardSummaries(context.Background(), append(negDashboardNames, posDashboardNames...)) // Then require.Error(t, err, "an error should be returned as not all dashboard name references are correct")