Вопрос или проблема
У меня есть форк программного обеспечения Polygon Edge, разработанного на Go v1.20. Проект использует golangci-lint в своих рабочих процессах GitHub Actions. Я включил golangci-lint, но сначала запустил его вручную как на оригинальном, так и на форкнутом проектах, чтобы сравнить результаты.
В оригинальном проекте ошибок не найдено. Однако в форкнутом проекте появилось множество ошибок — даже для идентичных файлов, что довольно необычно. Вот код из одного из затронутых файлов:
//nolint:forcetypeassert
package evm
import (
...
)
...
func opExp(c *state) {
x := c.pop()
y := c.top()
var gas uint64
if c.config.EIP158 {
gas = 50
} else {
gas = 10
}
gasCost := uint64((y.BitLen()+7)/8) * gas
if !c.consumeGas(gasCost) {
return
}
z := acquireBig().Set(one)
// https://www.programminglogic.com/fast-exponentiation-algorithms/
for _, d := range y.Bits() {
for i := 0; i < _W; i++ {
if d&1 == 1 {
toU256(z.Mul(z, x))
}
d >>= 1
toU256(x.Mul(x, x))
}
}
y.Set(z)
releaseBig(z)
}
func opAddMod(c *state) {
a := c.pop()
b := c.pop()
z := c.top()
if z.Sign() == 0 {
// деление на ноль
z.Set(zero)
} else {
a = a.Add(a, b)
z = z.Mod(a, z)
toU256(z)
}
}
func opMulMod(c *state) {
a := c.pop()
b := c.pop()
z := c.top()
if z.Sign() == 0 {
// деление на ноль
z.Set(zero)
} else {
a = a.Mul(a, b)
z = z.Mod(a, z)
toU256(z)
}
}
func opAnd(c *state) {
a := c.pop()
b := c.top()
b.And(a, b)
}
func opOr(c *state) {
a := c.pop()
b := c.top()
b.Or(a, b)
}
func opXor(c *state) {
a := c.pop()
b := c.top()
b.Xor(a, b)
}
var opByteMask = big.NewInt(255)
func opByte(c *state) {
x := c.pop()
y := c.top()
indx := x.Int64()
if indx > 31 {
y.Set(zero)
} else {
sh := (31 - indx) * 8
line,220: y.Rsh(y, uint(sh))
y.And(y, opByteMask)
}
}
func opNot(c *state) {
a := c.top()
a.Not(a)
toU256(a)
}
...
Я выполнил следующую команду: golangci-lint run --out-format=github-actions --timeout 10m --verbose
Результаты следующие:
- Оригинальный проект:
INFO golangci-lint has version v1.61.0 built with go1.23.2 from (unknown, modified: ?, mod sum: "h1:VvbOLaRVWmyxCnUIMTbf1kDsaJbTzH20FAMXTAlQGu8=") on (unknown)
INFO [config_reader] Config search paths: [./ /Users/vitomirpavlov/work/forks/polygon-edge /Users/vitomirpavlov/work/forks
/Users/vitomirpavlov/work/projects/project-node
/Users/vitomirpavlov/work/projects /Users/vitomirpavlov/work/projects /Users/vitomirpavlov /Users /]
INFO [config_reader] Used config file .golangci.yml
WARN [config_reader] The configuration option `run.skip-dirs` is deprecated, please use `issues.exclude-dirs`.
WARN [config_reader] The output format `github-actions` is deprecated, please use `colored-line-number`
INFO [lintersdb] Active 27 linters: [dogsled dupl errcheck errname errorlint forcetypeassert goconst gocritic godox gofmt goimports gosec importas lll makezero misspell nlreturn nolintlint prealloc predeclared stylecheck thelper tparallel unconvert wastedassign whitespace wsl]
INFO [loader] Go packages loading at mode 575 (compiled_files|exports_file|files|imports|deps|name|types_sizes) took 7.44611625s
INFO [runner/filename_unadjuster] Pre-built 0 adjustments in 44.592417ms
INFO [linters_context] importas settings found, but no aliases listed. List aliases under alias: key.
INFO [linters_context/goanalysis] analyzers took 0s with no stages
INFO [runner/skip_dirs] Skipped 9 issues from dir tests by pattern tests
INFO [runner/skip_dirs] Skipped 5 issues from dir helper/tests by pattern tests
INFO [runner] Issues before processing: 2771, after processing: 0
INFO [runner] Processors filtering stat (in/out): invalid_issue: 2771/2771, path_prettifier: 2771/2771, skip_dirs: 2771/2757, exclude-rules: 1756/845, uniq_by_line: 497/484, autogenerated_exclude: 2757/1756, identifier_marker: 1756/1756, exclude: 1756/1756, nolint: 845/497, diff: 484/0, cgo: 2771/2771, filename_unadjuster: 2771/2771
INFO [runner] processing took 449.635086ms with stages: diff: 311.677791ms, nolint: 74.901458ms, identifier_marker: 21.505708ms, exclude-rules: 20.301417ms, path_prettifier: 9.993584ms, autogenerated_exclude: 9.421166ms, skip_dirs: 1.468625ms, cgo: 125.5µs, invalid_issue: 100.75µs, uniq_by_line: 87.291µs, filename_unadjuster: 48.876µs, max_same_issues: 1.168µs, fixer: 291ns, exclude: 250ns, source_code: 209ns, sort_results: 209ns, max_per_file_from_linter: 208ns, skip_files: 167ns, path_shortener: 167ns, max_from_linter: 126ns, path_prefixer: 84ns, severity-rules: 41ns
INFO [runner] linters took 1.501898458s with stages: goanalysis_metalinter: 1.052092375s
INFO File cache stats: 0 entries of total size 0B
INFO Memory: 92 samples, avg is 37.5MB, max is 96.1MB
INFO Execution took 9.001672292s
- Форкнутый проект:
INFO golangci-lint has version v1.61.0 built with go1.23.2 from (unknown, modified: ?, mod sum: "h1:VvbOLaRVWmyxCnUIMTbf1kDsaJbTzH20FAMXTAlQGu8=") on (unknown)
INFO [config_reader] Config search paths: [./ /Users/vitomirpavlov/work/projects/project-node /Users/vitomirpavlov/work/projects /Users/vitomirpavlov/work/ /Users/vitomirpavlov/work /Users/vitomirpavlov /Users /]
INFO [config_reader] Used config file .golangci.yml
WARN [config_reader] The output format `github-actions` is deprecated, please use `colored-line-number`
INFO [lintersdb] Active 27 linters: [dogsled dupl errcheck errname errorlint forcetypeassert goconst gocritic godox gofmt goimports gosec importas lll makezero misspell nlreturn nolintlint prealloc predeclared stylecheck thelper tparallel unconvert wastedassign whitespace wsl]
INFO [loader] Go packages loading at mode 575 (deps|files|types_sizes|compiled_files|imports|name|exports_file) took 3.602814584s
INFO [runner/filename_unadjuster] Pre-built 0 adjustments in 41.664167ms
INFO [linters_context] importas settings found, but no aliases listed. List aliases under alias: key.
INFO [linters_context/goanalysis] analyzers took 0s with no stages
WARN [runner] Can't process result by diff processor: can't prepare diff by revgrep: could not read git repo: error executing "git diff --color=never --no-ext-diff --relative origin/develop --": exit status 128: fatal: bad revision 'origin/develop'
INFO [runner/skip_dirs] Skipped 5 issues from dir helper/tests by pattern tests
INFO [runner/skip_dirs] Skipped 10 issues from dir tests by pattern tests
INFO [runner/max_same_issues] 43/46 issues with text "G115: integer overflow conversion int -> uint64" were hidden, use --max-same-issues
INFO [runner/max_same_issues] 23/26 issues with text "G115: integer overflow conversion int64 -> uint64" were hidden, use --max-same-issues
INFO [runner/max_same_issues] 20/23 issues with text "G115: integer overflow conversion uint64 -> int64" were hidden, use --max-same-issues
INFO [runner/max_same_issues] 14/17 issues with text "assignments should only be cuddled with other assignments" were hidden, use --max-same-issues
INFO [runner/max_same_issues] 12/15 issues with text "only one cuddle assignment allowed before if statement" were hidden, use --max-same-issues
INFO [runner/max_same_issues] 12/15 issues with text "G115: integer overflow conversion uint64 -> int" were hidden, use --max-same-issues
INFO [runner/max_same_issues] 8/11 issues with text "expressions should not be cuddled with blocks" were hidden, use --max-same-issues
INFO [runner/max_same_issues] 7/10 issues with text "ifElseChain: rewrite if-else to switch statement" were hidden, use --max-same-issues
INFO [runner/max_same_issues] 6/9 issues with text "commentFormatting: put a space between `//` and comment text" were hidden, use --max-same-issues
INFO [runner/max_same_issues] 6/9 issues with text "type assertion must be checked" were hidden, use --max-same-issues
INFO [runner/max_same_issues] 2/5 issues with text "if statements should only be cuddled with assignments" were hidden, use --max-same-issues
INFO [runner/max_same_issues] 1/4 issues with text "unslice: could simplify buf[:] to buf" were hidden, use --max-same-issues
INFO [runner/max_same_issues] 1/4 issues with text "G115: integer overflow conversion int -> uint8" were hidden, use --max-same-issues
INFO [runner] Issues before processing: 2613, after processing: 103
INFO [runner] Processors filtering stat (in/out): max_same_issues: 258/103, max_from_linter: 103/103, source_code: 103/103, path_shortener: 103/103, path_prefixer: 103/103, invalid_issue: 2613/2613, identifier_marker: 1634/1634, max_per_file_from_linter: 258/258, uniq_by_line: 271/258, cgo: 2613/2613, filename_unadjuster: 2613/2613, exclude-rules: 1634/531, severity-rules: 103/103, fixer: 103/103, sort_results: 103/103, path_prettifier: 2613/2613, autogenerated_exclude: 2598/1634, nolint: 531/271, skip_files: 2613/2613, skip_dirs: 2613/2598, exclude: 1634/1634
INFO [runner] processing took 497.365834ms with stages: diff: 379.893458ms, nolint: 46.737834ms, path_prettifier: 22.076375ms, identifier_marker: 20.3875ms, exclude-rules: 15.325542ms, autogenerated_exclude: 9.250959ms, source_code: 1.650209ms, skip_dirs: 1.501666ms, max_same_issues: 184.542µs, invalid_issue: 97.792µs, cgo: 97.751µs, uniq_by_line: 47.666µs, filename_unadjuster: 47.542µs, max_from_linter: 29.083µs, max_per_file_from_linter: 22.167µs, path_shortener: 12.667µs, skip_files: 2.125µs, fixer: 333ns, exclude: 291ns, sort_results: 167ns, severity-rules: 83ns, path_prefixer: 82ns
INFO [runner] linters took 1.363894625s with stages: goanalysis_metalinter: 866.168459ms
...
::high file=helper/staking/staking.go,line=198,col=31::G115: integer overflow conversion int -> uint64 (gosec)
::error file=state/runtime/evm/instructions.go,line=1257,col=3::assignOp: replace `availableGas = availableGas - availableGas/64` with `availableGas -= availableGas/64` (gocritic)
::error file=state/runtime/evm/instructions.go,line=1016,col=2::assignOp: replace `size = size - 1` with `size--` (gocritic)
::error file=state/runtime/evm/instructions.go,line=468,col=2::ifElseChain: rewrite if-else to switch statement (gocritic)
::error file=state/runtime/evm/instructions.go,line=508,col=3::ifElseChain: rewrite if-else to switch statement (gocritic)
::error file=state/runtime/evm/instructions.go,line=521,col=3::ifElseChain: rewrite if-else to switch statement (gocritic)
::high file=state/runtime/evm/instructions.go,line=220,col=16::G115: integer overflow conversion int64 -> uint (gosec)
::high file=state/runtime/evm/instructions.go,line=315,col=14::G115: integer overflow conversion uint -> int (gosec)
::high file=state/runtime/evm/instructions.go,line=611,col=28::G115: integer overflow conversion int64 -> uint64 (gosec)
::high file=state/runtime/evm/instructions.go,line=956,col=13::G115: integer overflow conversion uint64 -> int (gosec)
::high file=state/runtime/evm/instructions.go,line=968,col=14::G115: integer overflow conversion uint64 -> int (gosec)
::high file=state/runtime/evm/state.go,line=330,col=50::G115: integer overflow conversion uint64 -> int (gosec)
::error file=state/runtime/evm/instructions.go,line=631,col=6::function min has same name as predeclared identifier (predeclared)
...
INFO File cache stats: 45 entries of total size 343.1KiB
INFO Memory: 52 samples, avg is 42.3MB, max is 100.6MB
INFO Execution took 5.018112166s
Версия линтера: golangci-lint has version v1.61.0 built with go1.23.2 from (unknown, modified: ?, mod sum: "h1:VvbOLaRVWmyxCnUIMTbf1kDsaJbTzH20FAMXTAlQGu8=") on (unknown)
Я пытался очистить кэш, проверял версии и всё, что приходит в голову, но ничего не сработало.
Ответ или решение
Вопрос различия результатов golangci-lint для одного и того же файла в различных проектах, даже при том, что они используют одну и ту же версию Go и golangci-lint, может вызывать недоумение. Давайте проанализируем возможные причины, основываясь на предоставленной информации.
Факторы, влияющие на различия в результатах
-
Конфигурационные файлы:
- Важно убедиться, что оба проекта используют идентичные файлы конфигурации .golangci.yml. Различия в этих файлах могут привести к отключению определенных линтеров или изменению их поведения.
- Проверьте, нет ли дополнительных настроек в forked проекте, которые могут изменять работу golangci-lint.
-
Изменения в коде:
- Убедитесь, что нет никакой разницы в файлах кода в обоих репозиториях. Даже мелкие отличия могут привести к различным результатам линтинга. Проведите сверку всех файлов, используя инструменты сравнения, такие как
diff
.
- Убедитесь, что нет никакой разницы в файлах кода в обоих репозиториях. Даже мелкие отличия могут привести к различным результатам линтинга. Проведите сверку всех файлов, используя инструменты сравнения, такие как
-
Зависимости и модули:
- Проверьте, что зависимости (включая версии) и модули, используемые в обоих проектах, совпадают. Различные версии библиотек могут влиять на результаты линтинга.
- Используйте команду
go mod tidy
для синхронизации зависимостей.
-
Флаги и параметры запуска:
- Возможно, в одном из проектов добавлены дополнительные флаги или параметры запуска для golangci-lint. Убедитесь, что команды, которые вы вводите, идентичны в обоих проектах.
-
Кэш golangci-lint:
- Иногда результаты могут кэшироваться, и это может привести к несоответствиям. Попробуйте очистить кэш с помощью команды
golangci-lint cache clear
.
- Иногда результаты могут кэшироваться, и это может привести к несоответствиям. Попробуйте очистить кэш с помощью команды
-
Проблемы с репозиторием Git:
- В сообщении о результатах линтинга для forked проекта присутствует ошибка, связанная с Git:
fatal: bad revision 'origin/develop'
. Это может обозначать проблемы с ветвлением или доступностью определённых изменений в вашем локальном репозитории. Убедитесь, что все изменения загружены и репозиторий находится в согласованном состоянии.
- В сообщении о результатах линтинга для forked проекта присутствует ошибка, связанная с Git:
-
Разница в окружении:
- Убедитесь, что окружения, в которых запускаются два проекта, идентичны. Различия в системах или установленных инструментах также могут привести к расхождениям в результатах.
Рекомендации по устранению проблемы
-
Сравнение конфигураций:
- Проверьте и сравните файлы конфигурации обоих проектов на наличие различий.
-
Обновление модулей:
- Убедитесь, что все модули актуальны. Используйте
go get -u
для обновления до последних стабильных версий.
- Убедитесь, что все модули актуальны. Используйте
-
Запуск линтинга на чистом проекте:
- Создайте новый проект и поэтапно добавляйте в него компоненты forked проекта, запуская golangci-lint после каждого добавления. Это поможет локализовать проблему.
-
Логи и отладка:
- Если разница в результатах не устраняется, создайте детальные логи выполнения и проанализируйте их на наличие отклонений.
Следуя этим рекомендациям, вы сможете выявить причины различий в результатах golangci-lint и принять необходимые меры для их устранения.