codeclimate-community/codeclimate-govet

Problem with exnternal dependencies and new version of codeclimate-govet

tmaczukin opened this issue · 0 comments

With the recent update of codeclimate-govet to a version that is compiled and executed in a Go 1.13 environment, the analyzer started to fail if any external dependency is used.

To reproduce the problem let's create a simple project:

mkdir /tmp/test-project
cd /tmp/test-project
go mod init test-project
cat > main.go <<EOF
package main

import (
        "fmt"

        "github.com/sirupsen/logrus"
)

func main() {
        fmt.Println("Test program")

        logrus.Info("Log line")
}

EOF
go build .
go mod tidy
./test-project

At this moment everything should work, go build should download the dependency and compile the binary and binary execution should be finished successfully.

Now, let's execute codeclimate-govet test using the official Docker image:

docker run --rm -t -i -v $(pwd):/code  codeclimate/codeclimate-govet
{"type":"issue","check_name":"GoVet/BugRisk","description":"9: cannot find package \"github.com/sirupsen/logrus\" in any of:","remediation_points":50000,"location":{"path":"main.go","lines":{"begin":6,"end":6}},"categories":["Bug Risk"]}Unexpected format for the following output:  /usr/local/go/src/github.com/sirupsen/logrus (from $GOROOT)

and it failed. It failed, because go vet call fails with:

docker run --rm -t -i -v $(pwd):/code  codeclimate/codeclimate-govet go vet /code/main.go
/code/main.go:6:9: cannot find package "github.com/sirupsen/logrus" in any of:
        /usr/local/go/src/github.com/sirupsen/logrus (from $GOROOT)
        /go/src/github.com/sirupsen/logrus (from $GOPATH)

Unfortunately, behavior of go vet changed between Go 1.13 and Go 1.9 which was the source of previously working version of the image:

docker run --rm -t -i -v $(pwd):/code  codeclimate/codeclimate-govet:b60

The behavior can be partially restored, when:

  1. go vet command (so also the codeclimate-govet) is executed from within the /code directory where the project is placed, and
  2. CGO_ENABLED=0 is set (otherwise exec: "gcc": executable file not found in $PATH error is thrown)
docker run --rm -t -i -v $(pwd):/code -e CGO_ENABLED=0 codeclimate/codeclimate-govet sh -c "cd /code && go vet main.go"
go: downloading github.com/sirupsen/logrus v1.4.2
go: extracting github.com/sirupsen/logrus v1.4.2
go: downloading github.com/stretchr/testify v1.2.2
go: downloading golang.org/x/sys v0.0.0-20190422165155-953cdadca894
go: extracting github.com/stretchr/testify v1.2.2
go: downloading github.com/davecgh/go-spew v1.1.1
go: downloading github.com/pmezard/go-difflib v1.0.0
go: extracting github.com/pmezard/go-difflib v1.0.0
go: extracting github.com/davecgh/go-spew v1.1.1
go: extracting golang.org/x/sys v0.0.0-20190422165155-953cdadca894
go: finding github.com/sirupsen/logrus v1.4.2
go: finding golang.org/x/sys v0.0.0-20190422165155-953cdadca894

This however, as can be seen in the example output above, causes go vet to download all dependencies, which next affects current expectations of codeclimate-govet binary:

docker run --rm -t -i -v $(pwd):/code -e CGO_ENABLED=0 codeclimate/codeclimate-govet sh -c "cd /code && /usr/src/app/codeclimate-govet"
Unexpected format for the following output: go: downloading github.com/sirupsen/logrus v1.4.2

Having all of the above in mind I've prepared a patch and build a custom version of codeclimate-govet image that works properly, being still based on Go 1.13:

patch
diff --git a/Dockerfile b/Dockerfile
index e5d055c..4273f03 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -26,5 +26,8 @@ COPY --from=build /usr/src/app/codeclimate-govet ./
 USER app
 
 VOLUME /code
+WORKDIR /code
+
+ENV CGO_ENABLED=0
 
 CMD ["/usr/src/app/codeclimate-govet"]
diff --git a/codeclimate-govet.go b/codeclimate-govet.go
index f4f9e6b..63dc5e1 100644
--- a/codeclimate-govet.go
+++ b/codeclimate-govet.go
@@ -24,6 +24,13 @@ func main() {
                os.Exit(1)
        }
 
+       downloadCmd := exec.Command("go", "mod", "download")
+       err = downloadCmd.Run()
+       if err != nil {
+               fmt.Fprintf(os.Stderr, "Error downloading dependencies: %v\n", err)
+               os.Exit(1)
+       }
+
        for _, path := range analysisFiles {
                cmd := exec.Command("go", "vet", path)

Executing codeclimate-vet test with this image works as expected:

docker run --rm -t -i -v $(pwd):/code codeclimate/codeclimate-govet:custom

The question now is: what can we do with this? Current behavior of codeclimate-govet is wrong and should be fixed. If the project contains any external dependency, the analyzer will start failing.

My patch proposed above does the job, but it looks more like a nasty hack than a proper solution.