mirror of
https://github.com/scratchfoundation/golangci-lint.git
synced 2025-07-10 03:34:04 -04:00
dev: fix CI workflow for Windows (#3134)
This commit is contained in:
parent
890a82659b
commit
bddc63a234
25 changed files with 280 additions and 77 deletions
.gitattributes
.github/workflows
Makefilepkg/result/processors
issues.gopath_prefixer.gopath_prefixer_test.gopath_unix.gopath_windows.goseverity_rules.goskip_files_test.go
test
2
.gitattributes
vendored
2
.gitattributes
vendored
|
@ -1 +1,3 @@
|
||||||
go.sum linguist-generated
|
go.sum linguist-generated
|
||||||
|
* text=auto eol=lf
|
||||||
|
*.ps1 text eol=crlf
|
||||||
|
|
6
.github/workflows/pr.yml
vendored
6
.github/workflows/pr.yml
vendored
|
@ -9,7 +9,7 @@ env:
|
||||||
GO_VERSION: 1.19
|
GO_VERSION: 1.19
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
# Check if there any dirty change for go mod tidy
|
# Check if there is any dirty change for go mod tidy
|
||||||
go-mod:
|
go-mod:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
@ -41,8 +41,7 @@ jobs:
|
||||||
# ex:
|
# ex:
|
||||||
# - 1.18beta1 -> 1.18.0-beta.1
|
# - 1.18beta1 -> 1.18.0-beta.1
|
||||||
# - 1.18rc1 -> 1.18.0-rc.1
|
# - 1.18rc1 -> 1.18.0-rc.1
|
||||||
# go-version: ${{ env.GO_VERSION }} # todo(ldez) uncomment after the next release v1.48.0
|
go-version: ${{ env.GO_VERSION }}
|
||||||
go-version: 1.18
|
|
||||||
- name: lint
|
- name: lint
|
||||||
uses: golangci/golangci-lint-action@v3.2.0
|
uses: golangci/golangci-lint-action@v3.2.0
|
||||||
with:
|
with:
|
||||||
|
@ -66,7 +65,6 @@ jobs:
|
||||||
go-version: ${{ env.GO_VERSION }} # test only the latest go version to speed up CI
|
go-version: ${{ env.GO_VERSION }} # test only the latest go version to speed up CI
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: make.exe test
|
run: make.exe test
|
||||||
continue-on-error: true
|
|
||||||
|
|
||||||
tests-on-macos:
|
tests-on-macos:
|
||||||
needs: golangci-lint # run after golangci-lint action to not produce duplicated errors
|
needs: golangci-lint # run after golangci-lint action to not produce duplicated errors
|
||||||
|
|
19
Makefile
19
Makefile
|
@ -4,17 +4,22 @@
|
||||||
# enable consistent Go 1.12/1.13 GOPROXY behavior.
|
# enable consistent Go 1.12/1.13 GOPROXY behavior.
|
||||||
export GOPROXY = https://proxy.golang.org
|
export GOPROXY = https://proxy.golang.org
|
||||||
|
|
||||||
|
BINARY = golangci-lint
|
||||||
|
ifeq ($(OS),Windows_NT)
|
||||||
|
BINARY := $(BINARY).exe
|
||||||
|
endif
|
||||||
|
|
||||||
# Build
|
# Build
|
||||||
|
|
||||||
build: golangci-lint
|
build: $(BINARY)
|
||||||
.PHONY: build
|
.PHONY: build
|
||||||
|
|
||||||
build_race:
|
build_race:
|
||||||
go build -race -o golangci-lint ./cmd/golangci-lint
|
go build -race -o $(BINARY) ./cmd/golangci-lint
|
||||||
.PHONY: build_race
|
.PHONY: build_race
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f golangci-lint
|
rm -f $(BINARY)
|
||||||
rm -f test/path
|
rm -f test/path
|
||||||
rm -f tools/Dracula.itermcolors
|
rm -f tools/Dracula.itermcolors
|
||||||
rm -f tools/goreleaser
|
rm -f tools/goreleaser
|
||||||
|
@ -25,7 +30,7 @@ clean:
|
||||||
# Test
|
# Test
|
||||||
test: export GOLANGCI_LINT_INSTALLED = true
|
test: export GOLANGCI_LINT_INSTALLED = true
|
||||||
test: build
|
test: build
|
||||||
GL_TEST_RUN=1 ./golangci-lint run -v
|
GL_TEST_RUN=1 ./$(BINARY) run -v
|
||||||
GL_TEST_RUN=1 go test -v -parallel 2 ./...
|
GL_TEST_RUN=1 go test -v -parallel 2 ./...
|
||||||
.PHONY: test
|
.PHONY: test
|
||||||
|
|
||||||
|
@ -36,7 +41,7 @@ test_fix: build
|
||||||
.PHONY: test_fix
|
.PHONY: test_fix
|
||||||
|
|
||||||
test_race: build_race
|
test_race: build_race
|
||||||
GL_TEST_RUN=1 ./golangci-lint run -v --timeout=5m
|
GL_TEST_RUN=1 ./$(BINARY) run -v --timeout=5m
|
||||||
.PHONY: test_race
|
.PHONY: test_race
|
||||||
|
|
||||||
test_linters:
|
test_linters:
|
||||||
|
@ -67,7 +72,7 @@ snapshot: .goreleaser.yml tools/goreleaser
|
||||||
|
|
||||||
# Non-PHONY targets (real files)
|
# Non-PHONY targets (real files)
|
||||||
|
|
||||||
golangci-lint: FORCE
|
$(BINARY): FORCE
|
||||||
go build -o $@ ./cmd/golangci-lint
|
go build -o $@ ./cmd/golangci-lint
|
||||||
|
|
||||||
tools/goreleaser: export GOFLAGS = -mod=readonly
|
tools/goreleaser: export GOFLAGS = -mod=readonly
|
||||||
|
@ -87,7 +92,7 @@ tools/Dracula.itermcolors:
|
||||||
assets/demo.svg: tools/svg-term tools/Dracula.itermcolors
|
assets/demo.svg: tools/svg-term tools/Dracula.itermcolors
|
||||||
./tools/svg-term --cast=183662 --out assets/demo.svg --window --width 110 --height 30 --from 2000 --to 20000 --profile ./tools/Dracula.itermcolors --term iterm2
|
./tools/svg-term --cast=183662 --out assets/demo.svg --window --width 110 --height 30 --from 2000 --to 20000 --profile ./tools/Dracula.itermcolors --term iterm2
|
||||||
|
|
||||||
assets/github-action-config.json: FORCE golangci-lint
|
assets/github-action-config.json: FORCE $(BINARY)
|
||||||
# go run ./scripts/gen_github_action_config/main.go $@
|
# go run ./scripts/gen_github_action_config/main.go $@
|
||||||
cd ./scripts/gen_github_action_config/; go run ./main.go ../../$@
|
cd ./scripts/gen_github_action_config/; go run ./main.go ../../$@
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
package processors
|
package processors
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"path/filepath"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
"github.com/golangci/golangci-lint/pkg/result"
|
"github.com/golangci/golangci-lint/pkg/result"
|
||||||
|
@ -48,15 +44,3 @@ func transformIssues(issues []result.Issue, transform func(i *result.Issue) *res
|
||||||
|
|
||||||
return retIssues
|
return retIssues
|
||||||
}
|
}
|
||||||
|
|
||||||
var separatorToReplace = regexp.QuoteMeta(string(filepath.Separator))
|
|
||||||
|
|
||||||
func normalizePathInRegex(path string) string {
|
|
||||||
if filepath.Separator == '/' {
|
|
||||||
return path
|
|
||||||
}
|
|
||||||
|
|
||||||
// This replacing should be safe because "/" are disallowed in Windows
|
|
||||||
// https://docs.microsoft.com/ru-ru/windows/win32/fileio/naming-a-file
|
|
||||||
return strings.ReplaceAll(path, "/", separatorToReplace)
|
|
||||||
}
|
|
|
@ -1,7 +1,7 @@
|
||||||
package processors
|
package processors
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"path"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/golangci/golangci-lint/pkg/result"
|
"github.com/golangci/golangci-lint/pkg/result"
|
||||||
)
|
)
|
||||||
|
@ -27,7 +27,7 @@ func (*PathPrefixer) Name() string {
|
||||||
func (p *PathPrefixer) Process(issues []result.Issue) ([]result.Issue, error) {
|
func (p *PathPrefixer) Process(issues []result.Issue) ([]result.Issue, error) {
|
||||||
if p.prefix != "" {
|
if p.prefix != "" {
|
||||||
for i := range issues {
|
for i := range issues {
|
||||||
issues[i].Pos.Filename = path.Join(p.prefix, issues[i].Pos.Filename)
|
issues[i].Pos.Filename = filepath.Join(p.prefix, issues[i].Pos.Filename)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return issues, nil
|
return issues, nil
|
||||||
|
|
|
@ -2,8 +2,10 @@ package processors
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go/token"
|
"go/token"
|
||||||
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/golangci/golangci-lint/pkg/result"
|
"github.com/golangci/golangci-lint/pkg/result"
|
||||||
|
@ -12,26 +14,40 @@ import (
|
||||||
func TestPathPrefixer_Process(t *testing.T) {
|
func TestPathPrefixer_Process(t *testing.T) {
|
||||||
paths := func(ps ...string) (issues []result.Issue) {
|
paths := func(ps ...string) (issues []result.Issue) {
|
||||||
for _, p := range ps {
|
for _, p := range ps {
|
||||||
issues = append(issues, result.Issue{Pos: token.Position{Filename: p}})
|
issues = append(issues, result.Issue{Pos: token.Position{Filename: filepath.FromSlash(p)}})
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range []struct {
|
for _, tt := range []struct {
|
||||||
name, prefix string
|
name, prefix string
|
||||||
issues, want []result.Issue
|
issues, want []result.Issue
|
||||||
}{
|
}{
|
||||||
{"empty prefix", "", paths("some/path", "cool"), paths("some/path", "cool")},
|
{
|
||||||
{"prefix", "ok", paths("some/path", "cool"), paths("ok/some/path", "ok/cool")},
|
name: "empty prefix",
|
||||||
{"prefix slashed", "ok/", paths("some/path", "cool"), paths("ok/some/path", "ok/cool")},
|
issues: paths("some/path", "cool"),
|
||||||
|
want: paths("some/path", "cool"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "prefix",
|
||||||
|
prefix: "ok",
|
||||||
|
issues: paths("some/path", "cool"),
|
||||||
|
want: paths("ok/some/path", "ok/cool"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "prefix slashed",
|
||||||
|
prefix: "ok/",
|
||||||
|
issues: paths("some/path", "cool"),
|
||||||
|
want: paths("ok/some/path", "ok/cool"),
|
||||||
|
},
|
||||||
} {
|
} {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
r := require.New(t)
|
|
||||||
|
|
||||||
p := NewPathPrefixer(tt.prefix)
|
p := NewPathPrefixer(tt.prefix)
|
||||||
got, err := p.Process(tt.issues)
|
|
||||||
r.NoError(err, "prefixer should never error")
|
|
||||||
|
|
||||||
r.Equal(got, tt.want)
|
got, err := p.Process(tt.issues)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, got, tt.want)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
8
pkg/result/processors/path_unix.go
Normal file
8
pkg/result/processors/path_unix.go
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
//go:build !windows
|
||||||
|
|
||||||
|
package processors
|
||||||
|
|
||||||
|
// normalizePathInRegex it's a noop function on Unix.
|
||||||
|
func normalizePathInRegex(path string) string {
|
||||||
|
return path
|
||||||
|
}
|
19
pkg/result/processors/path_windows.go
Normal file
19
pkg/result/processors/path_windows.go
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package processors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var separatorToReplace = regexp.QuoteMeta(string(filepath.Separator))
|
||||||
|
|
||||||
|
// normalizePathInRegex normalizes path in regular expressions.
|
||||||
|
// noop on Unix.
|
||||||
|
// This replacing should be safe because "/" are disallowed in Windows
|
||||||
|
// https://docs.microsoft.com/windows/win32/fileio/naming-a-file
|
||||||
|
func normalizePathInRegex(path string) string {
|
||||||
|
return strings.ReplaceAll(path, "/", separatorToReplace)
|
||||||
|
}
|
|
@ -49,7 +49,8 @@ func createSeverityRules(rules []SeverityRule, prefix string) []severityRule {
|
||||||
parsedRule.source = regexp.MustCompile(prefix + rule.Source)
|
parsedRule.source = regexp.MustCompile(prefix + rule.Source)
|
||||||
}
|
}
|
||||||
if rule.Path != "" {
|
if rule.Path != "" {
|
||||||
parsedRule.path = regexp.MustCompile(rule.Path)
|
path := normalizePathInRegex(rule.Path)
|
||||||
|
parsedRule.path = regexp.MustCompile(path)
|
||||||
}
|
}
|
||||||
parsedRules = append(parsedRules, parsedRule)
|
parsedRules = append(parsedRules, parsedRule)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@ package processors
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go/token"
|
"go/token"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -33,14 +35,15 @@ func TestSkipFiles(t *testing.T) {
|
||||||
|
|
||||||
processAssertEmpty(t, newTestSkipFiles(t, ".*"), newFileIssue("any.go"))
|
processAssertEmpty(t, newTestSkipFiles(t, ".*"), newFileIssue("any.go"))
|
||||||
|
|
||||||
processAssertEmpty(t, newTestSkipFiles(t, "a/b/c.go"), newFileIssue("a/b/c.go"))
|
cleanPath := strings.ReplaceAll(filepath.FromSlash("a/b/c.go"), `\`, `\\`)
|
||||||
processAssertSame(t, newTestSkipFiles(t, "a/b/c.go"), newFileIssue("a/b/d.go"))
|
processAssertEmpty(t, newTestSkipFiles(t, cleanPath), newFileIssue(filepath.FromSlash("a/b/c.go")))
|
||||||
|
processAssertSame(t, newTestSkipFiles(t, cleanPath), newFileIssue(filepath.FromSlash("a/b/d.go")))
|
||||||
|
|
||||||
processAssertEmpty(t, newTestSkipFiles(t, ".*\\.pb\\.go"), newFileIssue("a/b.pb.go"))
|
processAssertEmpty(t, newTestSkipFiles(t, ".*\\.pb\\.go"), newFileIssue(filepath.FromSlash("a/b.pb.go")))
|
||||||
processAssertSame(t, newTestSkipFiles(t, ".*\\.pb\\.go"), newFileIssue("a/b.go"))
|
processAssertSame(t, newTestSkipFiles(t, ".*\\.pb\\.go"), newFileIssue(filepath.FromSlash("a/b.go")))
|
||||||
|
|
||||||
processAssertEmpty(t, newTestSkipFiles(t, ".*\\.pb\\.go$"), newFileIssue("a/b.pb.go"))
|
processAssertEmpty(t, newTestSkipFiles(t, ".*\\.pb\\.go$"), newFileIssue(filepath.FromSlash("a/b.pb.go")))
|
||||||
processAssertSame(t, newTestSkipFiles(t, ".*\\.pb\\.go$"), newFileIssue("a/b.go"))
|
processAssertSame(t, newTestSkipFiles(t, ".*\\.pb\\.go$"), newFileIssue(filepath.FromSlash("a/b.go")))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSkipFilesInvalidPattern(t *testing.T) {
|
func TestSkipFilesInvalidPattern(t *testing.T) {
|
||||||
|
|
|
@ -12,6 +12,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFix(t *testing.T) {
|
func TestFix(t *testing.T) {
|
||||||
|
testshared.SkipOnWindows(t)
|
||||||
|
|
||||||
tmpDir := filepath.Join(testdataDir, "fix.tmp")
|
tmpDir := filepath.Join(testdataDir, "fix.tmp")
|
||||||
_ = os.RemoveAll(tmpDir) // cleanup previous runs
|
_ = os.RemoveAll(tmpDir) // cleanup previous runs
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,8 @@ func TestSourcesFromTestdata(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTypecheck(t *testing.T) {
|
func TestTypecheck(t *testing.T) {
|
||||||
|
testshared.SkipOnWindows(t)
|
||||||
|
|
||||||
testSourcesFromDir(t, filepath.Join(testdataDir, "notcompiles"))
|
testSourcesFromDir(t, filepath.Join(testdataDir, "notcompiles"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ package test
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -50,11 +49,11 @@ func TestOutput_Stderr(t *testing.T) {
|
||||||
Runner().
|
Runner().
|
||||||
Install().
|
Install().
|
||||||
Run().
|
Run().
|
||||||
ExpectHasIssue(expectedJSONOutput)
|
ExpectHasIssue(testshared.NormalizeFilePathInJSON(expectedJSONOutput))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOutput_File(t *testing.T) {
|
func TestOutput_File(t *testing.T) {
|
||||||
resultPath := path.Join(t.TempDir(), "golangci_lint_test_result")
|
resultPath := filepath.Join(t.TempDir(), "golangci_lint_test_result")
|
||||||
|
|
||||||
sourcePath := filepath.Join(testdataDir, "misspell.go")
|
sourcePath := filepath.Join(testdataDir, "misspell.go")
|
||||||
|
|
||||||
|
@ -74,7 +73,7 @@ func TestOutput_File(t *testing.T) {
|
||||||
|
|
||||||
b, err := os.ReadFile(resultPath)
|
b, err := os.ReadFile(resultPath)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Contains(t, string(b), expectedJSONOutput)
|
require.Contains(t, string(b), testshared.NormalizeFilePathInJSON(expectedJSONOutput))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOutput_Multiple(t *testing.T) {
|
func TestOutput_Multiple(t *testing.T) {
|
||||||
|
@ -94,5 +93,5 @@ func TestOutput_Multiple(t *testing.T) {
|
||||||
Run().
|
Run().
|
||||||
//nolint:misspell
|
//nolint:misspell
|
||||||
ExpectHasIssue("testdata/misspell.go:6:38: `occured` is a misspelling of `occurred`").
|
ExpectHasIssue("testdata/misspell.go:6:38: `occured` is a misspelling of `occurred`").
|
||||||
ExpectOutputContains(expectedJSONOutput)
|
ExpectOutputContains(testshared.NormalizeFilePathInJSON(expectedJSONOutput))
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ func TestNotExistingDirRun(t *testing.T) {
|
||||||
Run().
|
Run().
|
||||||
ExpectExitCode(exitcodes.Failure).
|
ExpectExitCode(exitcodes.Failure).
|
||||||
ExpectOutputContains("cannot find package").
|
ExpectOutputContains("cannot find package").
|
||||||
ExpectOutputContains("/testdata/no_such_dir")
|
ExpectOutputContains(testshared.NormalizeFileInString("/testdata/no_such_dir"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSymlinkLoop(t *testing.T) {
|
func TestSymlinkLoop(t *testing.T) {
|
||||||
|
|
2
test/testdata/depguard_ignore_file_rules.go
vendored
2
test/testdata/depguard_ignore_file_rules.go
vendored
|
@ -1,3 +1,5 @@
|
||||||
|
//go:build !windows
|
||||||
|
|
||||||
//golangcitest:args -Edepguard
|
//golangcitest:args -Edepguard
|
||||||
//golangcitest:config_path testdata/configs/depguard_ignore_file_rules.yml
|
//golangcitest:config_path testdata/configs/depguard_ignore_file_rules.yml
|
||||||
//golangcitest:expected_exitcode 0
|
//golangcitest:expected_exitcode 0
|
||||||
|
|
2
test/testdata/ifshort.go
vendored
2
test/testdata/ifshort.go
vendored
|
@ -1,3 +1,5 @@
|
||||||
|
//go:build !windows
|
||||||
|
|
||||||
//golangcitest:args -Eifshort --internal-cmd-test
|
//golangcitest:args -Eifshort --internal-cmd-test
|
||||||
package testdata
|
package testdata
|
||||||
|
|
||||||
|
|
1
test/testdata/tenv_go118.go
vendored
1
test/testdata/tenv_go118.go
vendored
|
@ -1,5 +1,4 @@
|
||||||
//go:build go1.18
|
//go:build go1.18
|
||||||
// +build go1.18
|
|
||||||
|
|
||||||
//golangcitest:args -Etenv
|
//golangcitest:args -Etenv
|
||||||
package testdata
|
package testdata
|
||||||
|
|
1
test/testdata/thelper_go118.go
vendored
1
test/testdata/thelper_go118.go
vendored
|
@ -1,5 +1,4 @@
|
||||||
//go:build go1.18
|
//go:build go1.18
|
||||||
// +build go1.18
|
|
||||||
|
|
||||||
//golangcitest:args -Ethelper
|
//golangcitest:args -Ethelper
|
||||||
package testdata
|
package testdata
|
||||||
|
|
|
@ -46,7 +46,7 @@ func Analyze(t *testing.T, sourcePath string, rawData []byte) {
|
||||||
|
|
||||||
var reportData jsonResult
|
var reportData jsonResult
|
||||||
err = json.Unmarshal(rawData, &reportData)
|
err = json.Unmarshal(rawData, &reportData)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err, string(rawData))
|
||||||
|
|
||||||
for _, issue := range reportData.Issues {
|
for _, issue := range reportData.Issues {
|
||||||
checkMessage(t, want, issue.Pos, "diagnostic", issue.FromLinter, issue.Text)
|
checkMessage(t, want, issue.Pos, "diagnostic", issue.FromLinter, issue.Text)
|
||||||
|
|
|
@ -15,7 +15,7 @@ import (
|
||||||
"github.com/golangci/golangci-lint/pkg/exitcodes"
|
"github.com/golangci/golangci-lint/pkg/exitcodes"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RunContext FIXME rename?
|
// RunContext the information extracted from directives.
|
||||||
type RunContext struct {
|
type RunContext struct {
|
||||||
Args []string
|
Args []string
|
||||||
ConfigPath string
|
ConfigPath string
|
||||||
|
@ -51,11 +51,8 @@ func ParseTestDirectives(tb testing.TB, sourcePath string) *RunContext {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.HasPrefix(line, "//go:build") || strings.HasPrefix(line, "// +build") {
|
if constraint.IsGoBuild(line) {
|
||||||
parse, err := constraint.Parse(line)
|
if !evaluateBuildTags(tb, line) {
|
||||||
require.NoError(tb, err)
|
|
||||||
|
|
||||||
if !parse.Eval(buildTagGoVersion) {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,6 +117,25 @@ func skipMultilineComment(scanner *bufio.Scanner) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// evaluateBuildTags Naive implementation of the evaluation of the build tags.
|
||||||
|
// Inspired by https://github.com/golang/go/blob/1dcef7b3bdcea4a829ea22c821e6a9484c325d61/src/cmd/go/internal/modindex/build.go#L914-L972
|
||||||
|
func evaluateBuildTags(tb testing.TB, line string) bool {
|
||||||
|
parse, err := constraint.Parse(line)
|
||||||
|
require.NoError(tb, err)
|
||||||
|
|
||||||
|
return parse.Eval(func(tag string) bool {
|
||||||
|
if tag == runtime.GOOS {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if buildTagGoVersion(tag) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func buildTagGoVersion(tag string) bool {
|
func buildTagGoVersion(tag string) bool {
|
||||||
vRuntime, err := hcversion.NewVersion(strings.TrimPrefix(runtime.Version(), "go"))
|
vRuntime, err := hcversion.NewVersion(strings.TrimPrefix(runtime.Version(), "go"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package testshared
|
package testshared
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -21,3 +22,61 @@ func TestParseTestDirectives(t *testing.T) {
|
||||||
}
|
}
|
||||||
assert.Equal(t, expected, rc)
|
assert.Equal(t, expected, rc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_evaluateBuildTags(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
desc string
|
||||||
|
tag string
|
||||||
|
assert assert.BoolAssertionFunc
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "",
|
||||||
|
tag: "// +build go1.18",
|
||||||
|
assert: assert.True,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "",
|
||||||
|
tag: "// +build go1.42",
|
||||||
|
assert: assert.False,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "",
|
||||||
|
tag: "//go:build go1.18",
|
||||||
|
assert: assert.True,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "",
|
||||||
|
tag: "//go:build go1.42",
|
||||||
|
assert: assert.False,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "",
|
||||||
|
tag: "//go:build " + runtime.GOOS,
|
||||||
|
assert: assert.True,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "",
|
||||||
|
tag: "//go:build !wondiws",
|
||||||
|
assert: assert.True,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "",
|
||||||
|
tag: "//go:build wondiws",
|
||||||
|
assert: assert.False,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "",
|
||||||
|
tag: "//go:build go1.18 && " + runtime.GOOS,
|
||||||
|
assert: assert.True,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testCases {
|
||||||
|
test := test
|
||||||
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
test.assert(t, evaluateBuildTags(t, test.tag))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -17,8 +17,6 @@ import (
|
||||||
"github.com/golangci/golangci-lint/pkg/logutils"
|
"github.com/golangci/golangci-lint/pkg/logutils"
|
||||||
)
|
)
|
||||||
|
|
||||||
const defaultBinPath = "../golangci-lint"
|
|
||||||
|
|
||||||
type RunnerBuilder struct {
|
type RunnerBuilder struct {
|
||||||
tb testing.TB
|
tb testing.TB
|
||||||
log logutils.Log
|
log logutils.Log
|
||||||
|
@ -43,7 +41,7 @@ func NewRunnerBuilder(tb testing.TB) *RunnerBuilder {
|
||||||
return &RunnerBuilder{
|
return &RunnerBuilder{
|
||||||
tb: tb,
|
tb: tb,
|
||||||
log: log,
|
log: log,
|
||||||
binPath: defaultBinPath,
|
binPath: defaultBinaryName(),
|
||||||
command: "run",
|
command: "run",
|
||||||
allowParallelRunners: true,
|
allowParallelRunners: true,
|
||||||
}
|
}
|
||||||
|
@ -68,7 +66,10 @@ func (b *RunnerBuilder) WithNoConfig() *RunnerBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *RunnerBuilder) WithConfigFile(cfgPath string) *RunnerBuilder {
|
func (b *RunnerBuilder) WithConfigFile(cfgPath string) *RunnerBuilder {
|
||||||
b.configPath = cfgPath
|
if cfgPath != "" {
|
||||||
|
b.configPath = filepath.FromSlash(cfgPath)
|
||||||
|
}
|
||||||
|
|
||||||
b.noConfig = cfgPath == ""
|
b.noConfig = cfgPath == ""
|
||||||
|
|
||||||
return b
|
return b
|
||||||
|
@ -293,17 +294,17 @@ func (r *RunnerResult) ExpectExitCode(possibleCodes ...int) *RunnerResult {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExpectOutputRegexp can be called with either a string or compiled regexp
|
// ExpectOutputRegexp can be called with either a string or compiled regexp
|
||||||
func (r *RunnerResult) ExpectOutputRegexp(s interface{}) *RunnerResult {
|
func (r *RunnerResult) ExpectOutputRegexp(s string) *RunnerResult {
|
||||||
r.tb.Helper()
|
r.tb.Helper()
|
||||||
|
|
||||||
assert.Regexp(r.tb, s, r.output, "exit code is %d", r.exitCode)
|
assert.Regexp(r.tb, normalizePathInRegex(s), r.output, "exit code is %d", r.exitCode)
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RunnerResult) ExpectOutputContains(s string) *RunnerResult {
|
func (r *RunnerResult) ExpectOutputContains(s string) *RunnerResult {
|
||||||
r.tb.Helper()
|
r.tb.Helper()
|
||||||
|
|
||||||
assert.Contains(r.tb, r.output, s, "exit code is %d", r.exitCode)
|
assert.Contains(r.tb, r.output, normalizeFilePath(s), "exit code is %d", r.exitCode)
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,7 +318,7 @@ func (r *RunnerResult) ExpectOutputNotContains(s string) *RunnerResult {
|
||||||
func (r *RunnerResult) ExpectOutputEq(s string) *RunnerResult {
|
func (r *RunnerResult) ExpectOutputEq(s string) *RunnerResult {
|
||||||
r.tb.Helper()
|
r.tb.Helper()
|
||||||
|
|
||||||
assert.Equal(r.tb, s, r.output, "exit code is %d", r.exitCode)
|
assert.Equal(r.tb, normalizeFilePath(s), r.output, "exit code is %d", r.exitCode)
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,10 +339,10 @@ func InstallGolangciLint(tb testing.TB) string {
|
||||||
tb.Log(string(output))
|
tb.Log(string(output))
|
||||||
}
|
}
|
||||||
|
|
||||||
require.NoError(tb, err, "Can't go install golangci-lint")
|
assert.NoError(tb, err, "Can't go install golangci-lint %s", string(output))
|
||||||
}
|
}
|
||||||
|
|
||||||
abs, err := filepath.Abs(defaultBinPath)
|
abs, err := filepath.Abs(defaultBinaryName())
|
||||||
require.NoError(tb, err)
|
require.NoError(tb, err)
|
||||||
|
|
||||||
return abs
|
return abs
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package testshared
|
package testshared
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"regexp"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -67,7 +67,7 @@ func TestRunnerBuilder_Runner(t *testing.T) {
|
||||||
"--internal-cmd-test",
|
"--internal-cmd-test",
|
||||||
"--allow-parallel-runners",
|
"--allow-parallel-runners",
|
||||||
"-c",
|
"-c",
|
||||||
"./testdata/example.yml",
|
filepath.FromSlash("./testdata/example.yml"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -82,7 +82,7 @@ func TestRunnerBuilder_Runner(t *testing.T) {
|
||||||
"--internal-cmd-test",
|
"--internal-cmd-test",
|
||||||
"--allow-parallel-runners",
|
"--allow-parallel-runners",
|
||||||
"-c",
|
"-c",
|
||||||
"testdata/example.yml",
|
filepath.FromSlash("testdata/example.yml"),
|
||||||
"-Efoo",
|
"-Efoo",
|
||||||
"--simple",
|
"--simple",
|
||||||
"--hello=world",
|
"--hello=world",
|
||||||
|
@ -140,7 +140,7 @@ func TestRunnerBuilder_Runner(t *testing.T) {
|
||||||
"--go=1.17",
|
"--go=1.17",
|
||||||
"--internal-cmd-test",
|
"--internal-cmd-test",
|
||||||
"--allow-parallel-runners",
|
"--allow-parallel-runners",
|
||||||
"testdata/all.go",
|
filepath.FromSlash("testdata/all.go"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -149,7 +149,7 @@ func TestRunnerBuilder_Runner(t *testing.T) {
|
||||||
builder: NewRunnerBuilder(t).
|
builder: NewRunnerBuilder(t).
|
||||||
WithRunContext(&RunContext{
|
WithRunContext(&RunContext{
|
||||||
Args: []string{"-Efoo", "--simple", "--hello=world"},
|
Args: []string{"-Efoo", "--simple", "--hello=world"},
|
||||||
ConfigPath: "testdata/example.yml",
|
ConfigPath: filepath.FromSlash("testdata/example.yml"),
|
||||||
ExpectedLinter: "test",
|
ExpectedLinter: "test",
|
||||||
}),
|
}),
|
||||||
expected: &Runner{
|
expected: &Runner{
|
||||||
|
@ -160,7 +160,7 @@ func TestRunnerBuilder_Runner(t *testing.T) {
|
||||||
"--internal-cmd-test",
|
"--internal-cmd-test",
|
||||||
"--allow-parallel-runners",
|
"--allow-parallel-runners",
|
||||||
"-c",
|
"-c",
|
||||||
"testdata/example.yml",
|
filepath.FromSlash("testdata/example.yml"),
|
||||||
"-Efoo",
|
"-Efoo",
|
||||||
"--simple",
|
"--simple",
|
||||||
"--hello=world",
|
"--hello=world",
|
||||||
|
@ -219,7 +219,6 @@ func TestRunnerResult_ExpectOutputNotContains(t *testing.T) {
|
||||||
|
|
||||||
func TestRunnerResult_ExpectOutputRegexp(t *testing.T) {
|
func TestRunnerResult_ExpectOutputRegexp(t *testing.T) {
|
||||||
r := &RunnerResult{tb: t, output: "this is an output"}
|
r := &RunnerResult{tb: t, output: "this is an output"}
|
||||||
r.ExpectOutputRegexp(regexp.MustCompile(`an.+`))
|
|
||||||
r.ExpectOutputRegexp(`an.+`)
|
r.ExpectOutputRegexp(`an.+`)
|
||||||
r.ExpectOutputRegexp("an")
|
r.ExpectOutputRegexp("an")
|
||||||
}
|
}
|
||||||
|
|
36
test/testshared/runner_unix.go
Normal file
36
test/testshared/runner_unix.go
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
//go:build !windows
|
||||||
|
|
||||||
|
package testshared
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SkipOnWindows it's a noop function on Unix.
|
||||||
|
func SkipOnWindows(_ testing.TB) {}
|
||||||
|
|
||||||
|
// NormalizeFilePathInJSON it's a noop function on Unix.
|
||||||
|
func NormalizeFilePathInJSON(in string) string {
|
||||||
|
return in
|
||||||
|
}
|
||||||
|
|
||||||
|
// NormalizeFileInString it's a noop function on Unix.
|
||||||
|
func NormalizeFileInString(in string) string {
|
||||||
|
return in
|
||||||
|
}
|
||||||
|
|
||||||
|
// defaultBinaryName returns the path to the default binary.
|
||||||
|
func defaultBinaryName() string {
|
||||||
|
return filepath.Join("..", "golangci-lint")
|
||||||
|
}
|
||||||
|
|
||||||
|
// normalizeFilePath it's a noop function on Unix.
|
||||||
|
func normalizeFilePath(in string) string {
|
||||||
|
return in
|
||||||
|
}
|
||||||
|
|
||||||
|
// normalizePathInRegex it's a noop function on Unix.
|
||||||
|
func normalizePathInRegex(path string) string {
|
||||||
|
return path
|
||||||
|
}
|
51
test/testshared/runner_windows.go
Normal file
51
test/testshared/runner_windows.go
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package testshared
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SkipOnWindows skip test on Windows.
|
||||||
|
func SkipOnWindows(tb testing.TB) {
|
||||||
|
tb.Skip("not supported on Windows")
|
||||||
|
}
|
||||||
|
|
||||||
|
// NormalizeFilePathInJSON find Go file path and replace `/` with `\\\\`.
|
||||||
|
func NormalizeFilePathInJSON(in string) string {
|
||||||
|
exp := regexp.MustCompile(`(?:^|\b)[\w-/.]+\.go`)
|
||||||
|
|
||||||
|
return exp.ReplaceAllStringFunc(in, func(s string) string {
|
||||||
|
return strings.ReplaceAll(s, "/", "\\\\")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// NormalizeFileInString normalizes in quoted string, ie. replace `\\` with `\\\\`.
|
||||||
|
func NormalizeFileInString(in string) string {
|
||||||
|
return strings.ReplaceAll(filepath.FromSlash(in), "\\", "\\\\")
|
||||||
|
}
|
||||||
|
|
||||||
|
// defaultBinaryName returns the path to the default binary.
|
||||||
|
func defaultBinaryName() string {
|
||||||
|
return filepath.Join("..", "golangci-lint.exe")
|
||||||
|
}
|
||||||
|
|
||||||
|
// normalizeFilePath find Go file path and replace `/` with `\\`.
|
||||||
|
func normalizeFilePath(in string) string {
|
||||||
|
exp := regexp.MustCompile(`(?:^|\b)[\w-/.]+\.go`)
|
||||||
|
|
||||||
|
return exp.ReplaceAllStringFunc(in, func(s string) string {
|
||||||
|
return strings.ReplaceAll(s, "/", "\\")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// normalizePathInRegex normalizes path in regular expressions.
|
||||||
|
// Replace all `/` with `\\`.
|
||||||
|
// This replacing should be safe because "/" are disallowed in Windows
|
||||||
|
// https://docs.microsoft.com/windows/win32/fileio/naming-a-file
|
||||||
|
func normalizePathInRegex(path string) string {
|
||||||
|
return strings.ReplaceAll(path, "/", regexp.QuoteMeta(string(filepath.Separator)))
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue