Skip to content

Commit

Permalink
fix(check-plugin): format output for indirect dependencies
Browse files Browse the repository at this point in the history
Fix the output of go mod directives from check-plugin command when
operating with --format / -f flag.

This now output go mod edit --replace directives for indirect
dependencies which ensures that the versions are correctly pinned.

Previously "fixes" were lost when go mod tidy was run.

Fixes #27
  • Loading branch information
stevenh committed Jul 10, 2024
1 parent 9ea9eba commit e7565ae
Show file tree
Hide file tree
Showing 8 changed files with 191 additions and 26 deletions.
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ require (
github.com/mattn/go-isatty v0.0.19
github.com/santhosh-tekuri/jsonschema/v5 v5.0.0
github.com/spf13/cobra v0.0.5
github.com/stretchr/testify v1.9.0
golang.org/x/mod v0.8.0
)

Expand Down Expand Up @@ -51,6 +52,7 @@ require (
github.com/cenkalti/backoff/v3 v3.2.2 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
github.com/clbanning/mxj v1.8.4 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dimchansky/utfbom v1.1.1 // indirect
github.com/fatih/color v1.13.0 // indirect
github.com/fsnotify/fsnotify v1.5.1 // indirect
Expand Down Expand Up @@ -123,6 +125,7 @@ require (
github.com/pelletier/go-toml v1.2.0 // indirect
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
github.com/pierrec/lz4 v2.6.1+incompatible // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rcrowley/go-metrics v0.0.0-20180406234716-d932a24a8ccb // indirect
github.com/ryanuber/go-glob v1.0.0 // indirect
github.com/sony/gobreaker v0.4.1 // indirect
Expand Down
5 changes: 3 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -772,8 +772,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
Expand All @@ -784,8 +784,9 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
Expand Down
78 changes: 56 additions & 22 deletions plugin.go
Original file line number Diff line number Diff line change
@@ -1,56 +1,90 @@
package cmd

import (
"fmt"
"os"
"path/filepath"

"github.com/krakendio/krakend-cobra/v2/plugin"
"github.com/spf13/cobra"
"golang.org/x/mod/modfile"
)

func pluginFunc(cmd *cobra.Command, _ []string) {
// indirectRequires returns the indirect dependencies of the go.sum file.
func indirectRequires(goSum string) (map[string]struct{}, error) {
dir := filepath.Dir(goSum)
filename := filepath.Join(dir, "go.mod")
data, err := os.ReadFile(filename)
if err != nil {
return nil, fmt.Errorf("read go.mod: %w", err)
}

f, err := modfile.Parse(filename, data, nil)
if err != nil {
return nil, fmt.Errorf("parse go.mod: %w", err)
}

indirects := map[string]struct{}{}
for _, r := range f.Require {
if r.Indirect {
indirects[r.Mod.Path] = struct{}{}
}
}

return indirects, nil
}

// getBuildInfo returns the dependencies of the binary calling it.
// It is a var to allow the replacement of the function in the tests
// as the debug.ReadBuildInfo function is not available in the tests
// https://github.com/golang/go/issues/68045
var localDescriber = plugin.Local

func pluginFunc(cmd *cobra.Command, _ []string) error {
f, err := os.Open(goSum)
if err != nil {
cmd.Println(err)
os.Exit(1)
return
return err
}

defer f.Close() //nolint:errcheck // Read only file so We would have returned an error before if this failed.

desc, err := plugin.Describe(f, goVersion, libcVersion)
if err != nil {
cmd.Println(err)
f.Close()
os.Exit(1)
return
return err
}

diffs := plugin.Local().Compare(desc)
diffs := localDescriber().Compare(desc)
if len(diffs) == 0 {
cmd.Println("No incompatibilities found!")
f.Close()
return
return nil
}

cmd.Println(len(diffs), "incompatibility(ies) found...")
if gogetEnabled {
indirects, err := indirectRequires(goSum)
if err != nil {
return err
}
for _, diff := range diffs {
if diff.Name != "go" && diff.Name != "libc" {
cmd.Printf("go get %s@%s\n", diff.Name, diff.Expected)
if _, ok := indirects[diff.Name]; ok {
cmd.Printf("go mod edit --replace %s=%s@%s\n", diff.Name, diff.Name, diff.Expected)
} else {
cmd.Printf("go get %s@%s\n", diff.Name, diff.Expected)
}
continue
}

cmd.Println(diff.Name)
cmd.Println("\thave:", diff.Have)
cmd.Println("\twant:", diff.Expected)
}
f.Close()
os.Exit(1)
} else {
for _, diff := range diffs {
cmd.Println(diff.Name)
cmd.Println("\thave:", diff.Have)
cmd.Println("\twant:", diff.Expected)
}
}

for _, diff := range diffs {
cmd.Println(diff.Name)
cmd.Println("\thave:", diff.Have)
cmd.Println("\twant:", diff.Expected)
}
f.Close()
os.Exit(1)
return fmt.Errorf("%d incompatibilities found", len(diffs))
}
90 changes: 90 additions & 0 deletions plugin_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package cmd

import (
"bytes"
"testing"

"github.com/krakendio/krakend-cobra/v2/plugin"
"github.com/spf13/cobra"
"github.com/stretchr/testify/require"
)

func Test_pluginFunc(t *testing.T) {
var buf bytes.Buffer
cmd := &cobra.Command{}
cmd.SetOutput(&buf)

localDescriber = func() plugin.Descriptor {
return plugin.Descriptor{
Go: goVersion,
Libc: libcVersion,
Deps: map[string]string{
"golang.org/x/mod": "v0.6.0-dev.0.20220419223038-86c51ed26bb4",
"github.com/Azure/azure-sdk-for-go": "v59.3.0+incompatible",
"cloud.google.com/go": "v0.100.2",
},
}
}

defer func() { localDescriber = plugin.Local }()

tests := map[string]struct {
goSum string
expected string
fix bool
err string
}{
"missing": {
goSum: "./testdata/missing-go.sum",
err: "open ./testdata/missing-go.sum: no such file or directory",
},
"matching": {
goSum: "./testdata/match-go.sum",
expected: "No incompatibilities found!\n",
},
"changes": {
goSum: "./testdata/changes-go.sum",
expected: `cloud.google.com/go
have: v0.100.3
want: v0.100.2
github.com/Azure/azure-sdk-for-go
have: v59.3.1+incompatible
want: v59.3.0+incompatible
golang.org/x/mod
have: v0.6.10-dev.0.20220419223038-86c51ed26bb4
want: v0.6.0-dev.0.20220419223038-86c51ed26bb4
`,
err: "3 incompatibilities found",
},
"fix": {
goSum: "./testdata/changes-go.sum",
fix: true,
expected: `go mod edit --replace cloud.google.com/go=cloud.google.com/[email protected]
go mod edit --replace github.com/Azure/azure-sdk-for-go=github.com/Azure/[email protected]+incompatible
go get golang.org/x/[email protected]
`,
err: "3 incompatibilities found",
},
}
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
buf.Reset()

orig := goSum
goSum = tc.goSum
defer func() { goSum = orig }()

fix := gogetEnabled
gogetEnabled = tc.fix
defer func() { gogetEnabled = fix }()

err := pluginFunc(cmd, nil)
if tc.err != "" {
require.EqualError(t, err, tc.err)
} else {
require.NoError(t, err)
}
require.Equal(t, tc.expected, buf.String())
})
}
}
4 changes: 2 additions & 2 deletions root.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ var (
Use: "check-plugin",
Short: "Checks your plugin dependencies are compatible.",
Long: "Checks your plugin dependencies are compatible and proposes commands to update your dependencies.",
Run: pluginFunc,
RunE: pluginFunc,
Example: "krakend check-plugin -g 1.19.0 -s ./go.sum -f",
}

Expand Down Expand Up @@ -106,7 +106,7 @@ func init() {
portFlag := IntFlagBuilder(&port, "port", "p", 0, "Listening port for the http service")
RunCommand = NewCommand(runCmd, cfgFlag, debugFlag, portFlag)

goSumFlag := StringFlagBuilder(&goSum, "sum", "s", goSum, "Path to the go.sum file to analize")
goSumFlag := StringFlagBuilder(&goSum, "sum", "s", goSum, "Path to the go.sum file to analyze")
goVersionFlag := StringFlagBuilder(&goVersion, "go", "g", goVersion, "The version of the go compiler used for your plugin")
libcVersionFlag := StringFlagBuilder(&libcVersion, "libc", "l", "", "Version of the libc library used")
gogetFlag := BoolFlagBuilder(&gogetEnabled, "format", "f", false, "Shows fix commands to update your dependencies")
Expand Down
12 changes: 12 additions & 0 deletions testdata/changes-go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=
cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=
cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U=
cloud.google.com/go v0.100.3 h1:t9Iw5QH5v4XtlEQaCtUY7x6sCABps8sW0acw7e2WQ6Y=
cloud.google.com/go v0.100.3/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A=
github.com/Azure/azure-sdk-for-go v51.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go v59.3.1+incompatible h1:dPIm0BO4jsMXFcCI/sLTPkBtE7mk8WMuRHA0JeWhlcQ=
github.com/Azure/azure-sdk-for-go v59.3.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.6.10-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
golang.org/x/mod v0.6.10-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
13 changes: 13 additions & 0 deletions testdata/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module github.com/krakendio/krakend-cobra/v2

go 1.17

require (
github.com/gin-gonic/gin v1.8.2
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4
)

require (
cloud.google.com/go v0.100.2 // indirect
github.com/Azure/azure-sdk-for-go v59.3.0+incompatible // indirect
)
12 changes: 12 additions & 0 deletions testdata/match-go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=
cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=
cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U=
cloud.google.com/go v0.100.2 h1:t9Iw5QH5v4XtlEQaCtUY7x6sCABps8sW0acw7e2WQ6Y=
cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A=
github.com/Azure/azure-sdk-for-go v51.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go v59.3.0+incompatible h1:dPIm0BO4jsMXFcCI/sLTPkBtE7mk8WMuRHA0JeWhlcQ=
github.com/Azure/azure-sdk-for-go v59.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=

0 comments on commit e7565ae

Please sign in to comment.