
Run CI on mac os only with go1.13 and on windows only on go1.14. Speed up tests. Introduce --allow-parallel-runners. Block on parallel run lock 5s instead of 60s. Don't invalidate analysis cache for minor config changes.
150 lines
3.6 KiB
Go
150 lines
3.6 KiB
Go
package testshared
|
|
|
|
import (
|
|
"io/ioutil"
|
|
"os"
|
|
"os/exec"
|
|
"strings"
|
|
"sync"
|
|
"syscall"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/golangci/golangci-lint/pkg/exitcodes"
|
|
"github.com/golangci/golangci-lint/pkg/logutils"
|
|
)
|
|
|
|
type LintRunner struct {
|
|
t assert.TestingT
|
|
log logutils.Log
|
|
env []string
|
|
installOnce sync.Once
|
|
}
|
|
|
|
func NewLintRunner(t assert.TestingT, environ ...string) *LintRunner {
|
|
log := logutils.NewStderrLog("test")
|
|
log.SetLevel(logutils.LogLevelInfo)
|
|
return &LintRunner{
|
|
t: t,
|
|
log: log,
|
|
env: environ,
|
|
}
|
|
}
|
|
|
|
func (r *LintRunner) Install() {
|
|
r.installOnce.Do(func() {
|
|
if os.Getenv("GOLANGCI_LINT_INSTALLED") == "true" {
|
|
return
|
|
}
|
|
|
|
cmd := exec.Command("make", "-C", "..", "build")
|
|
assert.NoError(r.t, cmd.Run(), "Can't go install golangci-lint")
|
|
})
|
|
}
|
|
|
|
type RunResult struct {
|
|
t assert.TestingT
|
|
|
|
output string
|
|
exitCode int
|
|
}
|
|
|
|
func (r *RunResult) ExpectNoIssues() {
|
|
assert.Equal(r.t, "", r.output, "exit code is %d", r.exitCode)
|
|
assert.Equal(r.t, exitcodes.Success, r.exitCode, "output is %s", r.output)
|
|
}
|
|
|
|
func (r *RunResult) ExpectExitCode(possibleCodes ...int) *RunResult {
|
|
for _, pc := range possibleCodes {
|
|
if pc == r.exitCode {
|
|
return r
|
|
}
|
|
}
|
|
|
|
assert.Fail(r.t, "invalid exit code", "exit code (%d) must be one of %v: %s", r.exitCode, possibleCodes, r.output)
|
|
return r
|
|
}
|
|
|
|
func (r *RunResult) ExpectOutputContains(s string) *RunResult {
|
|
assert.Contains(r.t, r.output, s, "exit code is %d", r.exitCode)
|
|
return r
|
|
}
|
|
|
|
func (r *RunResult) ExpectOutputEq(s string) *RunResult {
|
|
assert.Equal(r.t, s, r.output, "exit code is %d", r.exitCode)
|
|
return r
|
|
}
|
|
|
|
func (r *RunResult) ExpectHasIssue(issueText string) *RunResult {
|
|
return r.ExpectExitCode(exitcodes.IssuesFound).ExpectOutputContains(issueText)
|
|
}
|
|
|
|
func (r *LintRunner) Run(args ...string) *RunResult {
|
|
newArgs := append([]string{"--allow-parallel-runners"}, args...)
|
|
return r.RunCommand("run", newArgs...)
|
|
}
|
|
|
|
func (r *LintRunner) RunCommand(command string, args ...string) *RunResult {
|
|
r.Install()
|
|
|
|
runArgs := append([]string{command}, args...)
|
|
defer func(startedAt time.Time) {
|
|
r.log.Infof("ran [../golangci-lint %s] in %s", strings.Join(runArgs, " "), time.Since(startedAt))
|
|
}(time.Now())
|
|
|
|
cmd := exec.Command("../golangci-lint", runArgs...)
|
|
cmd.Env = append(os.Environ(), r.env...)
|
|
out, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
if exitError, ok := err.(*exec.ExitError); ok {
|
|
r.log.Infof("stderr: %s", exitError.Stderr)
|
|
ws := exitError.Sys().(syscall.WaitStatus)
|
|
return &RunResult{
|
|
t: r.t,
|
|
output: string(out),
|
|
exitCode: ws.ExitStatus(),
|
|
}
|
|
}
|
|
|
|
r.t.Errorf("can't get error code from %s", err)
|
|
return nil
|
|
}
|
|
|
|
// success, exitCode should be 0 if go is ok
|
|
ws := cmd.ProcessState.Sys().(syscall.WaitStatus)
|
|
return &RunResult{
|
|
t: r.t,
|
|
output: string(out),
|
|
exitCode: ws.ExitStatus(),
|
|
}
|
|
}
|
|
|
|
func (r *LintRunner) RunWithYamlConfig(cfg string, args ...string) *RunResult {
|
|
newArgs := append([]string{"--allow-parallel-runners"}, args...)
|
|
return r.RunCommandWithYamlConfig(cfg, "run", newArgs...)
|
|
}
|
|
|
|
func (r *LintRunner) RunCommandWithYamlConfig(cfg, command string, args ...string) *RunResult {
|
|
f, err := ioutil.TempFile("", "golangci_lint_test")
|
|
assert.NoError(r.t, err)
|
|
f.Close()
|
|
|
|
cfgPath := f.Name() + ".yml"
|
|
err = os.Rename(f.Name(), cfgPath)
|
|
assert.NoError(r.t, err)
|
|
|
|
if os.Getenv("GL_KEEP_TEMP_FILES") != "1" {
|
|
defer os.Remove(cfgPath)
|
|
}
|
|
|
|
cfg = strings.TrimSpace(cfg)
|
|
cfg = strings.Replace(cfg, "\t", " ", -1)
|
|
|
|
err = ioutil.WriteFile(cfgPath, []byte(cfg), os.ModePerm)
|
|
assert.NoError(r.t, err)
|
|
|
|
pargs := append([]string{"-c", cfgPath}, args...)
|
|
return r.RunCommand(command, pargs...)
|
|
}
|