diff --git a/.golangci.yml b/.golangci.yml index 090e12151..ad06ff5bd 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,9 +1,8 @@ +version: "2" run: concurrency: 2 - timeout: 10m linters: - enable-all: false - disable-all: true + default: none enable: - copyloopvar - depguard @@ -11,73 +10,74 @@ linters: - errorlint - gocritic - gocyclo - - gofumpt - - goimports - gomodguard - - revive - - gosimple - govet - ineffassign - lll - misspell - nakedret - nolintlint + - revive - staticcheck - testifylint - - typecheck - unconvert - unparam - unused -linters-settings: - revive: - rules: - - name: package-comments - disabled: true - depguard: - rules: - all: - deny: - - pkg: io/ioutil - desc: 'io/ioutil package has been deprecated' - - pkg: gopkg.in/yaml.v2 - desc: 'compose-go uses yaml.v3' - gomodguard: - blocked: - modules: - - github.com/pkg/errors: - recommendations: - - errors - - fmt - versions: - - github.com/distribution/distribution: - reason: "use distribution/reference" - - gotest.tools: - version: "< 3.0.0" - reason: "deprecated, pre-modules version" - gocritic: - # Enable multiple checks by tags, run `GL_DEBUG=gocritic golangci-lint run` to see all tags and checks. - # Empty list by default. See https://github.com/go-critic/go-critic#usage -> section "Tags". - enabled-tags: - - diagnostic - - opinionated - - style - disabled-checks: - - paramTypeCombine - - unnamedResult - - whyNoLint - gocyclo: - min-complexity: 16 - lll: - line-length: 200 + settings: + depguard: + rules: + all: + deny: + - pkg: io/ioutil + desc: io/ioutil package has been deprecated + - pkg: gopkg.in/yaml.v2 + desc: compose-go uses yaml.v3 + gocritic: + disabled-checks: + - paramTypeCombine + - unnamedResult + - whyNoLint + enabled-tags: + - diagnostic + - opinionated + - style + gocyclo: + min-complexity: 16 + gomodguard: + blocked: + modules: + - github.com/pkg/errors: + recommendations: + - errors + - fmt + versions: + - github.com/distribution/distribution: + reason: use distribution/reference + - gotest.tools: + version: < 3.0.0 + reason: deprecated, pre-modules version + lll: + line-length: 200 + revive: + rules: + - name: package-comments + disabled: true + exclusions: + generated: lax + paths: + - third_party$ + - builtin$ + - examples$ issues: - # golangci hides some golint warnings (the warning about exported things - # without documentation for example), this will make it show them anyway. - exclude-use-default: false - # Maximum issues count per one linter. - # Set to 0 to disable. - # Default: 50 max-issues-per-linter: 0 - # Maximum count of issues with the same text. - # Set to 0 to disable. - # Default: 3 max-same-issues: 0 +formatters: + enable: + - gofumpt + - goimports + exclusions: + generated: lax + paths: + - third_party$ + - builtin$ + - examples$ diff --git a/Dockerfile b/Dockerfile index 92fb8c5fa..69ff7f1c0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,7 +17,7 @@ ARG GO_VERSION=1.23.6 ARG XX_VERSION=1.6.1 -ARG GOLANGCI_LINT_VERSION=v1.63.4 +ARG GOLANGCI_LINT_VERSION=v2.0.2 ARG ADDLICENSE_VERSION=v1.0.0 ARG BUILD_TAGS="e2e" diff --git a/cmd/compose/compose.go b/cmd/compose/compose.go index a3cc24517..8bd1bccbe 100644 --- a/cmd/compose/compose.go +++ b/cmd/compose/compose.go @@ -550,10 +550,7 @@ func RootCommand(dockerCli command.Cli, backend Backend) *cobra.Command { //noli } composeCmd := cmd - for { - if composeCmd.Name() == PluginName { - break - } + for composeCmd.Name() != PluginName { if !composeCmd.HasParent() { return fmt.Errorf("error parsing command line, expected %q", PluginName) } diff --git a/cmd/compose/exec.go b/cmd/compose/exec.go index aa6774d5d..a6a8847ea 100644 --- a/cmd/compose/exec.go +++ b/cmd/compose/exec.go @@ -86,7 +86,7 @@ func runExec(ctx context.Context, dockerCli command.Cli, backend api.Service, op if err != nil { return err } - projectOptions, err := opts.composeOptions.toProjectOptions() + projectOptions, err := opts.composeOptions.toProjectOptions() //nolint:staticcheck if err != nil { return err } diff --git a/cmd/compose/options.go b/cmd/compose/options.go index 3b6ba1beb..0df72cd85 100644 --- a/cmd/compose/options.go +++ b/cmd/compose/options.go @@ -246,7 +246,7 @@ func displayInterpolationVariables(writer io.Writer, varsInfo []varInfo) { } func displayLocationRemoteStack(dockerCli command.Cli, project *types.Project, options buildOptions) { - mainComposeFile := options.ProjectOptions.ConfigPaths[0] + mainComposeFile := options.ProjectOptions.ConfigPaths[0] //nolint:staticcheck if ui.Mode != ui.ModeQuiet && ui.Mode != ui.ModeJSON { _, _ = fmt.Fprintf(dockerCli.Out(), "Your compose stack %q is stored in %q\n", mainComposeFile, project.WorkingDir) } @@ -258,8 +258,8 @@ func confirmRemoteIncludes(dockerCli command.Cli, options buildOptions, assumeYe } var remoteIncludes []string - remoteLoaders := options.ProjectOptions.remoteLoaders(dockerCli) - for _, cf := range options.ProjectOptions.ConfigPaths { + remoteLoaders := options.ProjectOptions.remoteLoaders(dockerCli) //nolint:staticcheck + for _, cf := range options.ProjectOptions.ConfigPaths { //nolint:staticcheck for _, loader := range remoteLoaders { if loader.Accept(cf) { remoteIncludes = append(remoteIncludes, cf) diff --git a/cmd/compose/top_test.go b/cmd/compose/top_test.go index 277219902..a2172a061 100644 --- a/cmd/compose/top_test.go +++ b/cmd/compose/top_test.go @@ -220,8 +220,8 @@ func TestRunTopCore(t *testing.T) { t.Run(tc.name, func(t *testing.T) { header, entries := collectTop([]api.ContainerProcSummary{summary}) - assert.EqualValues(t, tc.header, header) - assert.EqualValues(t, tc.entries, entries) + assert.Equal(t, tc.header, header) + assert.Equal(t, tc.entries, entries) var buf bytes.Buffer err := topPrint(&buf, header, entries) @@ -233,7 +233,7 @@ func TestRunTopCore(t *testing.T) { t.Run("all", func(t *testing.T) { header, entries := collectTop(all) - assert.EqualValues(t, topHeader{ + assert.Equal(t, topHeader{ "SERVICE": 0, "#": 1, "UID": 2, @@ -246,7 +246,7 @@ func TestRunTopCore(t *testing.T) { "GID": 9, "CMD": 10, }, header) - assert.EqualValues(t, []topEntries{ + assert.Equal(t, []topEntries{ { "SERVICE": "simple", "#": "1", diff --git a/cmd/formatter/shortcut.go b/cmd/formatter/shortcut.go index d6674e8d1..126d4509f 100644 --- a/cmd/formatter/shortcut.go +++ b/cmd/formatter/shortcut.go @@ -238,7 +238,7 @@ func (lk *LogKeyboard) openDockerDesktop(ctx context.Context, project *types.Pro link := fmt.Sprintf("docker-desktop://dashboard/apps/%s", project.Name) err := open.Run(link) if err != nil { - err = fmt.Errorf("Could not open Docker Desktop") + err = fmt.Errorf("could not open Docker Desktop") lk.keyboardError("View", err) } return err @@ -255,7 +255,7 @@ func (lk *LogKeyboard) openDDComposeUI(ctx context.Context, project *types.Proje link := fmt.Sprintf("docker-desktop://dashboard/docker-compose/%s", project.Name) err := open.Run(link) if err != nil { - err = fmt.Errorf("Could not open Docker Desktop Compose UI") + err = fmt.Errorf("could not open Docker Desktop Compose UI") lk.keyboardError("View Config", err) } return err @@ -269,7 +269,7 @@ func (lk *LogKeyboard) openDDWatchDocs(ctx context.Context, project *types.Proje link := fmt.Sprintf("docker-desktop://dashboard/docker-compose/%s/watch", project.Name) err := open.Run(link) if err != nil { - err = fmt.Errorf("Could not open Docker Desktop Compose UI") + err = fmt.Errorf("could not open Docker Desktop Compose UI") lk.keyboardError("Watch Docs", err) } return err @@ -299,7 +299,7 @@ func (lk *LogKeyboard) StartWatch(ctx context.Context, doneCh chan bool, project eg.Go(tracing.EventWrapFuncForErrGroup(ctx, "menu/watch", tracing.SpanOptions{}, func(ctx context.Context) error { if options.Create.Build == nil { - err := fmt.Errorf("Cannot run watch mode with flag --no-build") + err := fmt.Errorf("cannot run watch mode with flag --no-build") lk.keyboardError("Watch", err) return err } diff --git a/pkg/compose/convergence.go b/pkg/compose/convergence.go index da14323e9..d56ff40a4 100644 --- a/pkg/compose/convergence.go +++ b/pkg/compose/convergence.go @@ -47,7 +47,7 @@ import ( const ( doubledContainerNameWarning = "WARNING: The %q service is using the custom container name %q. " + "Docker requires each container to have a unique name. " + - "Remove the custom name to scale the service.\n" + "Remove the custom name to scale the service" ) // convergence manages service's container lifecycle. diff --git a/pkg/compose/create.go b/pkg/compose/create.go index ddd4898cb..2a92f92e3 100644 --- a/pkg/compose/create.go +++ b/pkg/compose/create.go @@ -486,7 +486,7 @@ func parseSecurityOpts(p *types.Project, securityOpts []string) ([]string, bool, if strings.Contains(opt, ":") { con = strings.SplitN(opt, ":", 2) } else { - return securityOpts, false, fmt.Errorf("Invalid security-opt: %q", opt) + return securityOpts, false, fmt.Errorf("invalid security-opt: %q", opt) } } if con[0] == "seccomp" && con[1] != "unconfined" && con[1] != "builtin" { @@ -997,10 +997,10 @@ func buildContainerConfigMounts(p types.Project, s types.ServiceConfig) ([]mount } if definedConfig.Driver != "" { - return nil, errors.New("Docker Compose does not support configs.*.driver") + return nil, errors.New("Docker Compose does not support configs.*.driver") //nolint:staticcheck } if definedConfig.TemplateDriver != "" { - return nil, errors.New("Docker Compose does not support configs.*.template_driver") + return nil, errors.New("Docker Compose does not support configs.*.template_driver") //nolint:staticcheck } if definedConfig.Environment != "" || definedConfig.Content != "" { @@ -1047,10 +1047,10 @@ func buildContainerSecretMounts(p types.Project, s types.ServiceConfig) ([]mount } if definedSecret.Driver != "" { - return nil, errors.New("Docker Compose does not support secrets.*.driver") + return nil, errors.New("Docker Compose does not support secrets.*.driver") //nolint:staticcheck } if definedSecret.TemplateDriver != "" { - return nil, errors.New("Docker Compose does not support secrets.*.template_driver") + return nil, errors.New("Docker Compose does not support secrets.*.template_driver") //nolint:staticcheck } if definedSecret.Environment != "" { diff --git a/pkg/compose/ls.go b/pkg/compose/ls.go index 706bcf0d5..34d3ceb0e 100644 --- a/pkg/compose/ls.go +++ b/pkg/compose/ls.go @@ -70,7 +70,7 @@ func combinedConfigFiles(containers []container.Summary) (string, error) { for _, c := range containers { files, ok := c.Labels[api.ConfigFilesLabel] if !ok { - return "", fmt.Errorf("No label %q set on container %q of compose project", api.ConfigFilesLabel, c.ID) + return "", fmt.Errorf("no label %q set on container %q of compose project", api.ConfigFilesLabel, c.ID) } for _, f := range strings.Split(files, ",") { @@ -120,7 +120,7 @@ func groupContainerByLabel(containers []container.Summary, labelName string) (ma for _, c := range containers { label, ok := c.Labels[labelName] if !ok { - return nil, nil, fmt.Errorf("No label %q set on container %q of compose project", labelName, c.ID) + return nil, nil, fmt.Errorf("no label %q set on container %q of compose project", labelName, c.ID) } labelContainers, ok := containersByLabel[label] if !ok { diff --git a/pkg/compose/ls_test.go b/pkg/compose/ls_test.go index 214f8c40f..847814c6f 100644 --- a/pkg/compose/ls_test.go +++ b/pkg/compose/ls_test.go @@ -104,7 +104,7 @@ func TestCombinedConfigFiles(t *testing.T) { }{ "project1": {ConfigFiles: "/home/docker-compose.yaml", Error: nil}, "project2": {ConfigFiles: "/home/project2-docker-compose.yaml", Error: nil}, - "project3": {ConfigFiles: "", Error: fmt.Errorf("No label %q set on container %q of compose project", api.ConfigFilesLabel, "service4")}, + "project3": {ConfigFiles: "", Error: fmt.Errorf("no label %q set on container %q of compose project", api.ConfigFilesLabel, "service4")}, } for project, containers := range containersByLabel { diff --git a/pkg/compose/watch.go b/pkg/compose/watch.go index fd8a61ebd..85b722af3 100644 --- a/pkg/compose/watch.go +++ b/pkg/compose/watch.go @@ -754,7 +754,7 @@ func (s *composeService) imageCreatedTime(ctx context.Context, project *types.Pr return time.Now(), err } if len(containers) == 0 { - return time.Now(), fmt.Errorf("Could not get created time for service's image") + return time.Now(), fmt.Errorf("could not get created time for service's image") } img, err := s.apiClient().ImageInspect(ctx, containers[0].ImageID) diff --git a/pkg/e2e/up_test.go b/pkg/e2e/up_test.go index 6a927f0aa..65fecca30 100644 --- a/pkg/e2e/up_test.go +++ b/pkg/e2e/up_test.go @@ -98,7 +98,7 @@ func TestUpDependenciesNotStopped(t *testing.T) { if exitErr.ExitCode() == -1 { t.Fatalf("`compose up` was killed: %v", err) } - require.EqualValues(t, 130, exitErr.ExitCode()) + require.Equal(t, 130, exitErr.ExitCode()) } RequireServiceState(t, c, "app", "exited") diff --git a/pkg/watch/notify_test.go b/pkg/watch/notify_test.go index 9146c3c49..9b68c4d05 100644 --- a/pkg/watch/notify_test.go +++ b/pkg/watch/notify_test.go @@ -149,7 +149,7 @@ func TestGitBranchSwitch(t *testing.T) { f.assertEvents(path) // Make sure there are no errors in the out stream - assert.Equal(t, "", f.out.String()) + assert.Empty(t, f.out.String()) } func TestWatchesAreRecursive(t *testing.T) { diff --git a/pkg/watch/watcher_naive.go b/pkg/watch/watcher_naive.go index 5cacd2205..1e03b810c 100644 --- a/pkg/watch/watcher_naive.go +++ b/pkg/watch/watcher_naive.go @@ -274,7 +274,7 @@ func newWatcher(paths []string) (Notify, error) { fsw, err := fsnotify.NewWatcher() if err != nil { if strings.Contains(err.Error(), "too many open files") && runtime.GOOS == "linux" { - return nil, fmt.Errorf("Hit OS limits creating a watcher.\n" + + return nil, fmt.Errorf("hit OS limits creating a watcher.\n" + "Run 'sysctl fs.inotify.max_user_instances' to check your inotify limits.\n" + "To raise them, run 'sudo sysctl fs.inotify.max_user_instances=1024'") } @@ -317,7 +317,7 @@ func greatestExistingAncestors(paths []string) ([]string, error) { for _, p := range paths { newP, err := greatestExistingAncestor(p) if err != nil { - return nil, fmt.Errorf("Finding ancestor of %s: %w", p, err) + return nil, fmt.Errorf("finding ancestor of %s: %w", p, err) } result = append(result, newP) }