Skip to content

gci and gofumpt fix to duplicate imports #4885

Closed
@scop

Description

@scop

Welcome

  • Yes, I'm using a binary release within 2 latest releases. Only such installations are supported.
  • Yes, I've searched similar issues on GitHub and didn't find any.
  • Yes, I've read the typecheck section of the FAQ.
  • Yes, I've tried with the standalone linter if available (e.g., gocritic, go vet, etc.).
  • I agree to follow this project's Code of Conduct

Description of the problem

In some cases, having both gci and gofumpt enabled results in duplicate imports, when they both would attempt to make the same fix.

Neither linter has this problem when run separately (even with golangci-lint), so I think this is a golangci-lint one.

Unfortunately gofumpt does not seem to have an option to not do its import manipulation.

Version of golangci-lint

$ golangci-lint --version
golangci-lint has version 1.59.1 built with go1.22.3 from 1a55854a on 2024-06-09T18:08:33Z

Configuration

linters:
  disable-all: true
  enable:
    - gci
    - gofumpt
golangci-lint --fix

Go environment

$ go version && go env
go version go1.22.5 linux/amd64
GO111MODULE=''
GOARCH='amd64'
GOBIN=''
GOCACHE='[...]/.cache/go-build'
GOENV='[...]/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMODCACHE='[...]/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='[...]/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='[...]/go/1.22.5'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='[...]/go/1.22.5/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.22.5'
GCCGO='gccgo'
GOAMD64='v1'
AR='ar'
CC='gcc'
CXX='g++'
CGO_ENABLED='1'
GOMOD='[...]/go.mod'
GOWORK=''
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build1436578552=/tmp/go-build -gno-record-gcc-switches'

Verbose output of running

$ golangci-lint cache clean
$ golangci-lint run -v
INFO golangci-lint has version 1.59.1 built with go1.22.3 from 1a55854a on 2024-06-09T18:08:33Z 
INFO [config_reader] Config search paths: [./ /[...]] 
INFO [config_reader] Used config file .golangci.yml 
INFO [lintersdb] Active 2 linters: [gci gofumpt]  
INFO [loader] Go packages loading at mode 7 (files|name|compiled_files) took 144.091214ms 
INFO [runner/filename_unadjuster] Pre-built 0 adjustments in 1.584109ms 
INFO [linters_context/goanalysis] analyzers took 260.091173ms with top 10 stages: gci: 108.732328ms, modinfo: 86.154764ms, gofumpt: 63.752141ms, typecheck: 1.45194ms 
INFO [runner] Line 6 has multiple issues but at least one of them isn't inline: []result.Issue{result.Issue{FromLinter:"gci", Text:"File is not `gci`-ed with --skip-generated -s standard -s default", Severity:"", SourceLines:[]string{"\t\"net/http\""}, Replacement:(*result.Replacement)(0xc00075fcd0), Pkg:(*packages.Package)(0xc00023c480), LineRange:(*result.Range)(nil), Pos:token.Position{Filename:"foo.go", Offset:0, Line:6, Column:0}, HunkPos:0, ExpectNoLint:false, ExpectedNoLintLinter:""}, result.Issue{FromLinter:"gofumpt", Text:"File is not `gofumpt`-ed", Severity:"", SourceLines:[]string{"\t\"net/http\""}, Replacement:(*result.Replacement)(0xc00190c610), Pkg:(*packages.Package)(0xc00023c480), LineRange:(*result.Range)(nil), Pos:token.Position{Filename:"foo.go", Offset:0, Line:6, Column:0}, HunkPos:0, ExpectNoLint:false, ExpectedNoLintLinter:""}} 
INFO [runner] Fix issue &result.Issue{FromLinter:"gofumpt", Text:"File is not `gofumpt`-ed", Severity:"", SourceLines:[]string{"\t\"fmt\""}, Replacement:(*result.Replacement)(0xc0017934d0), Pkg:(*packages.Package)(0xc00023c480), LineRange:(*result.Range)(nil), Pos:token.Position{Filename:"foo.go", Offset:0, Line:4, Column:0}, HunkPos:0, ExpectNoLint:false, ExpectedNoLintLinter:""} with range {4 4} 
INFO [runner] Fix issue &result.Issue{FromLinter:"gci", Text:"File is not `gci`-ed with --skip-generated -s standard -s default", Severity:"", SourceLines:[]string{"\t\"github.com/golangci/golangci-lint/pkg/exitcodes\""}, Replacement:(*result.Replacement)(0xc00075fc90), Pkg:(*packages.Package)(0xc00023c480), LineRange:(*result.Range)(nil), Pos:token.Position{Filename:"foo.go", Offset:0, Line:5, Column:0}, HunkPos:0, ExpectNoLint:false, ExpectedNoLintLinter:""} with range {5 5} 
INFO [runner] Fix issue &result.Issue{FromLinter:"gci", Text:"File is not `gci`-ed with --skip-generated -s standard -s default", Severity:"", SourceLines:[]string{"\t\"net/http\""}, Replacement:(*result.Replacement)(0xc00075fcd0), Pkg:(*packages.Package)(0xc00023c480), LineRange:(*result.Range)(nil), Pos:token.Position{Filename:"foo.go", Offset:0, Line:6, Column:0}, HunkPos:0, ExpectNoLint:false, ExpectedNoLintLinter:""} with range {6 6} 
INFO [runner] fixer took 324.348µs with stages: all: 324.348µs 
INFO [runner] Issues before processing: 4, after processing: 0 
INFO [runner] Processors filtering stat (out/in): invalid_issue: 4/4, path_prettifier: 4/4, exclude: 4/4, diff: 4/4, max_per_file_from_linter: 4/4, max_same_issues: 4/4, max_from_linter: 4/4, source_code: 4/4, cgo: 4/4, skip_dirs: 4/4, autogenerated_exclude: 4/4, identifier_marker: 4/4, nolint: 4/4, uniq_by_line: 4/4, filename_unadjuster: 4/4, skip_files: 4/4, exclude-rules: 4/4, path_shortener: 4/4, severity-rules: 4/4, fixer: 0/4 
INFO [runner] processing took 663.703µs with stages: fixer: 341.289µs, exclude-rules: 85.931µs, identifier_marker: 85.46µs, nolint: 59.181µs, path_prettifier: 28.363µs, autogenerated_exclude: 26.189µs, source_code: 18.415µs, skip_dirs: 8.736µs, cgo: 1.643µs, path_shortener: 1.623µs, invalid_issue: 1.383µs, max_from_linter: 1.122µs, uniq_by_line: 852ns, filename_unadjuster: 831ns, max_same_issues: 741ns, skip_files: 361ns, max_per_file_from_linter: 351ns, sort_results: 321ns, exclude: 320ns, diff: 261ns, path_prefixer: 190ns, severity-rules: 140ns 
INFO [runner] linters took 36.39709ms with stages: goanalysis_metalinter: 35.664507ms 
INFO File cache stats: 1 entries of total size 172B 
INFO Memory: 3 samples, avg is 31.2MB, max is 40.1MB 
INFO Execution took 188.214548ms  

A minimal reproducible example or link to a public repository

package main

import (
	"fmt"
	"github.com/golangci/golangci-lint/pkg/exitcodes"
	"net/http"
)

func main() {
	fmt.Println(exitcodes.Success)
	fmt.Println(http.StatusOK)
}

With both gci and gofumpt enabled, formatted imports block becomes

import (
	"fmt"
	"net/http"

	"net/http"

	"github.com/golangci/golangci-lint/pkg/exitcodes"
)

Validation

  • Yes, I've included all information above (version, config, etc.).

Supporter

Metadata

Metadata

Assignees

No one assigned

    Labels

    duplicateThis issue or pull request already exists

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions